Systemy liczbowe (BIN, OCT, HEX), NWD (Euklides), badanie pierwszosci - zaawansowane cwiczenia
ð Podstawa programowa: I.2aW informatyce kluczowe sa cztery systemy liczbowe. Komputer operuje na bitach (systemie dwojkowym), ale programisci czesto uzywaja systemu osemkowego i szesnastkowego jako wygodnego skrotu.
Przyklad: 42(10) na BIN
42 / 2 = 21 reszta 0
21 / 2 = 10 reszta 1
10 / 2 = 5 reszta 0
5 / 2 = 2 reszta 1
2 / 2 = 1 reszta 0
1 / 2 = 0 reszta 1
Czytamy reszty od dolu: 42(10) = 101010(2)
Sprawdzenie: 1*32 + 0*16 + 1*8 + 0*4 + 1*2 + 0*1 = 32+8+2 = 42 ✓
Grupujemy bity po 4 (od prawej) i zamieniamy na cyfry HEX:
1010 1100 0011(2)
A C 3
= AC3(16)
Tabela konwersji (4 bity -> HEX):
0000=0 0001=1 0010=2 0011=3
0100=4 0101=5 0110=6 0111=7
1000=8 1001=9 1010=A 1011=B
1100=C 1101=D 1110=E 1111=F
def dec_na_bin(n):
"""Konwersja dziesietna na dwojkowa"""
if n == 0:
return "0"
wynik = ""
while n > 0:
wynik = str(n % 2) + wynik
n //= 2
return wynik
def dec_na_hex(n):
"""Konwersja dziesietna na szesnastkowa"""
if n == 0:
return "0"
hex_cyfry = "0123456789ABCDEF"
wynik = ""
while n > 0:
wynik = hex_cyfry[n % 16] + wynik
n //= 16
return wynik
def dowolna_na_dec(tekst, baza):
"""Konwersja z dowolnej bazy na dziesietna"""
cyfry = "0123456789ABCDEF"
wynik = 0
for znak in tekst.upper():
wynik = wynik * baza + cyfry.index(znak)
return wynik
# Testy
print(f"42 DEC = {dec_na_bin(42)} BIN") # 101010
print(f"42 DEC = {dec_na_hex(42)} HEX") # 2A
print(f"101010 BIN = {dowolna_na_dec('101010', 2)} DEC") # 42
print(f"2A HEX = {dowolna_na_dec('2A', 16)} DEC") # 42
# Wbudowane funkcje Pythona:
print(bin(42)) # 0b101010
print(oct(42)) # 0o52
print(hex(42)) # 0x2a
print(int('101010', 2)) # 42
print(int('2A', 16)) # 42
Najwiekszy Wspolny Dzielnik (NWD) dwoch liczb to najwieksza liczba, ktora dzieli obie bez reszty. Algorytm Euklidesa (ok. 300 p.n.e.) to jeden z najstarszych znanych algorytmow i wciaz jeden z najelegantszych.
# NWD - wersja iteracyjna
def nwd(a, b):
while b != 0:
a, b = b, a % b
return a
# NWD - wersja rekurencyjna
def nwd_rek(a, b):
if b == 0:
return a
return nwd_rek(b, a % b)
# Najmniejsza Wspolna Wielokrotnosc
def nww(a, b):
return a * b // nwd(a, b)
# Testy
print(f"NWD(48, 18) = {nwd(48, 18)}") # 6
print(f"NWD(100, 75) = {nwd(100, 75)}") # 25
print(f"NWW(12, 8) = {nww(12, 8)}") # 24
# Rozszerzony algorytm Euklidesa
# Znajduje x, y takie ze: a*x + b*y = NWD(a,b)
def nwd_rozszerzony(a, b):
if b == 0:
return a, 1, 0
d, x, y = nwd_rozszerzony(b, a % b)
return d, y, x - (a // b) * y
d, x, y = nwd_rozszerzony(48, 18)
print(f"NWD(48,18) = {d}, 48*{x} + 18*{y} = {48*x + 18*y}")
Liczba pierwsza to liczba naturalna wieksza od 1, ktora dzieli sie tylko przez 1 i przez siebie. Badanie pierwszosci ma ogromne znaczenie w kryptografii (np. RSA).
# Metoda naiwna - O(n)
def czy_pierwsza_naiwna(n):
if n < 2:
return False
for i in range(2, n):
if n % i == 0:
return False
return True
# Metoda zoptymalizowana - O(sqrt(n))
def czy_pierwsza(n):
if n < 2:
return False
if n < 4:
return True
if n % 2 == 0 or n % 3 == 0:
return False
i = 5
while i * i <= n:
if n % i == 0 or n % (i + 2) == 0:
return False
i += 6
return True
# Sito Eratostenesa - znajdz WSZYSTKIE liczby pierwsze do n
def sito_eratostenesa(n):
jest_pierwsza = [True] * (n + 1)
jest_pierwsza[0] = jest_pierwsza[1] = False
i = 2
while i * i <= n:
if jest_pierwsza[i]:
for j in range(i * i, n + 1, i):
jest_pierwsza[j] = False
i += 1
return [i for i in range(n + 1) if jest_pierwsza[i]]
# Testy
print(f"17 pierwsza? {czy_pierwsza(17)}") # True
print(f"21 pierwsza? {czy_pierwsza(21)}") # False
print(f"Pierwsze do 50: {sito_eratostenesa(50)}")
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
# Rozklad na czynniki pierwsze
def rozklad(n):
czynniki = []
d = 2
while d * d <= n:
while n % d == 0:
czynniki.append(d)
n //= d
d += 1
if n > 1:
czynniki.append(n)
return czynniki
print(f"Rozklad 360 = {rozklad(360)}") # [2, 2, 2, 3, 3, 5]
Napisz program, ktory pobiera od uzytkownika liczbe i system (DEC/BIN/OCT/HEX), a nastepnie wyswietla te liczbe we wszystkich czterech systemach. Zaimplementuj konwersje samodzielnie (bez bin/oct/hex).
def na_dec(tekst, baza):
cyfry = "0123456789ABCDEF"
wynik = 0
for z in tekst.upper():
wynik = wynik * baza + cyfry.index(z)
return wynik
def z_dec(n, baza):
if n == 0:
return "0"
cyfry = "0123456789ABCDEF"
wynik = ""
while n > 0:
wynik = cyfry[n % baza] + wynik
n //= baza
return wynik
# Pobranie danych
liczba_txt = input("Podaj liczbe: ")
system = input("System (DEC/BIN/OCT/HEX): ").upper()
bazy = {"DEC": 10, "BIN": 2, "OCT": 8, "HEX": 16}
dec_wartosc = na_dec(liczba_txt, bazy[system])
print(f"\nWyniki konwersji:")
print(f"DEC: {dec_wartosc}")
print(f"BIN: {z_dec(dec_wartosc, 2)}")
print(f"OCT: {z_dec(dec_wartosc, 8)}")
print(f"HEX: {z_dec(dec_wartosc, 16)}")
Napisz funkcje nwd_wielu(lista) i nww_wielu(lista), ktore obliczaja NWD i NWW dowolnej ilosci liczb. Przetestuj na [12, 18, 24], [100, 75, 50, 25] i [7, 13, 23].
def nwd(a, b):
while b != 0:
a, b = b, a % b
return a
def nww(a, b):
return a * b // nwd(a, b)
def nwd_wielu(lista):
wynik = lista[0]
for i in range(1, len(lista)):
wynik = nwd(wynik, lista[i])
return wynik
def nww_wielu(lista):
wynik = lista[0]
for i in range(1, len(lista)):
wynik = nww(wynik, lista[i])
return wynik
# Testy
listy = [[12, 18, 24], [100, 75, 50, 25], [7, 13, 23]]
for l in listy:
print(f"NWD{l} = {nwd_wielu(l)}")
print(f"NWW{l} = {nww_wielu(l)}")
print()
# NWD[12, 18, 24] = 6 NWW = 72
# NWD[100, 75, 50, 25] = 25 NWW = 300
# NWD[7, 13, 23] = 1 NWW = 2093
Uzyj sita Eratostenesa do znalezienia wszystkich liczb pierwszych do 1000. Nastepnie: a) Ile jest liczb pierwszych do 1000? b) Jaka jest najwieksza "luka" (roznica miedzy kolejnymi pierwszymi)? c) Ile jest "blizniat pierwszych" (par rozniaccych sie o 2, np. 11 i 13)?
def sito(n):
jest_p = [True] * (n + 1)
jest_p[0] = jest_p[1] = False
i = 2
while i * i <= n:
if jest_p[i]:
for j in range(i * i, n + 1, i):
jest_p[j] = False
i += 1
return [i for i in range(n + 1) if jest_p[i]]
pierwsze = sito(1000)
# a) Ile liczb pierwszych do 1000
print(f"a) Liczb pierwszych do 1000: {len(pierwsze)}")
# 168
# b) Najwieksza luka
max_luka = 0
para_luka = (0, 0)
for i in range(1, len(pierwsze)):
luka = pierwsze[i] - pierwsze[i-1]
if luka > max_luka:
max_luka = luka
para_luka = (pierwsze[i-1], pierwsze[i])
print(f"b) Najwieksza luka: {max_luka} (miedzy {para_luka[0]} a {para_luka[1]})")
# c) Bliznieta pierwsze
bliznieta = []
for i in range(1, len(pierwsze)):
if pierwsze[i] - pierwsze[i-1] == 2:
bliznieta.append((pierwsze[i-1], pierwsze[i]))
print(f"c) Bliznieta pierwsze: {len(bliznieta)} par")
print(f" Pierwsze 10: {bliznieta[:10]}")
# (3,5), (5,7), (11,13), (17,19), (29,31), ...
Napisz program, ktory wykonuje operacje arytmetyczne (dodawanie, odejmowanie, mnozenie) na liczbach podanych w systemie dwojkowym. Wynik tez wyswietl w BIN. Zaimplementuj dodawanie binarne "recznie" (bit po bicie z przenoszeniem).
def dodaj_bin(a_bin, b_bin):
"""Dodawanie binarne bit po bicie"""
# Wyrownaj dlugosci
max_len = max(len(a_bin), len(b_bin))
a_bin = a_bin.zfill(max_len)
b_bin = b_bin.zfill(max_len)
wynik = ""
przeniesienie = 0
# Dodawanie od prawej do lewej
for i in range(max_len - 1, -1, -1):
bit_a = int(a_bin[i])
bit_b = int(b_bin[i])
suma = bit_a + bit_b + przeniesienie
wynik = str(suma % 2) + wynik
przeniesienie = suma // 2
if przeniesienie:
wynik = "1" + wynik
return wynik
def bin_na_dec(b):
wynik = 0
for c in b:
wynik = wynik * 2 + int(c)
return wynik
def dec_na_bin(n):
if n == 0:
return "0"
wynik = ""
while n > 0:
wynik = str(n % 2) + wynik
n //= 2
return wynik
# Kalkulator
a_bin = input("Pierwsza liczba (BIN): ")
op = input("Operacja (+, -, *): ")
b_bin = input("Druga liczba (BIN): ")
a_dec = bin_na_dec(a_bin)
b_dec = bin_na_dec(b_bin)
if op == '+':
wynik_bin = dodaj_bin(a_bin, b_bin)
wynik_dec = a_dec + b_dec
elif op == '-':
wynik_dec = a_dec - b_dec
wynik_bin = dec_na_bin(abs(wynik_dec))
if wynik_dec < 0:
wynik_bin = "-" + wynik_bin
elif op == '*':
wynik_dec = a_dec * b_dec
wynik_bin = dec_na_bin(wynik_dec)
print(f"\n{a_bin}({a_dec}) {op} {b_bin}({b_dec})")
print(f"= {wynik_bin} (DEC: {wynik_dec})")
# Przyklad:
# 1010 (10) + 1101 (13) = 10111 (23)
# 1100 (12) * 101 (5) = 111100 (60)