Liceum Klasa III 45 minut PP: I.2a | s. 342

Lekcja 15: Algorytmy - powtorzenie i utrwalenie (systemy liczbowe, NWD)

Systemy liczbowe (BIN, OCT, HEX), NWD (Euklides), badanie pierwszosci - zaawansowane cwiczenia

📋 Podstawa programowa: I.2a
NWDNWWalgorytmykonwersjapierwszosc liczbypowtorzeniesystemy liczboweutrwalenie
00:00
Wprowadzenie
5 min
00:05
Teoria
15 min
00:20
Cwiczenia
15 min
00:35
Podsumowanie
10 min
📚

Teoria

Systemy liczbowe

W informatyce kluczowe sa cztery systemy liczbowe. Komputer operuje na bitach (systemie dwojkowym), ale programisci czesto uzywaja systemu osemkowego i szesnastkowego jako wygodnego skrotu.

Systemy liczbowe:
Dziesietny (DEC) - baza 10, cyfry 0-9 (uzywamy na co dzien)
Dwojkowy (BIN) - baza 2, cyfry 0-1 (wewnatrz komputera)
Osemkowy (OCT) - baza 8, cyfry 0-7 (uprawnienia plikow w Linux)
Szesnastkowy (HEX) - baza 16, cyfry 0-9, A-F (kolory, adresy pamieci)

Konwersja DEC na BIN (metoda dzielenia przez 2)

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 ✓

Konwersja BIN na HEX

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

Implementacja w Pythonie

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

Algorytm Euklidesa - NWD

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.

Zasada algorytmu Euklidesa:
NWD(a, b) = NWD(b, a mod b), dopoki b != 0
Gdy b = 0, NWD = a

Przyklad: NWD(48, 18)
NWD(48, 18) -> NWD(18, 48 mod 18) = NWD(18, 12)
NWD(18, 12) -> NWD(12, 18 mod 12) = NWD(12, 6)
NWD(12, 6) -> NWD(6, 12 mod 6) = NWD(6, 0)
b = 0, wiec NWD = 6
# 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}")

Badanie pierwszosci liczb

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]
✏️

Zadania

Latwe

Zadanie 1: Konwerter systemow liczbowych

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).

Pokaz rozwiazanie
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)}")
Srednie

Zadanie 2: NWD i NWW wielu liczb

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].

Pokaz rozwiazanie
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
Srednie

Zadanie 3: Analiza liczb pierwszych

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)?

Pokaz rozwiazanie
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), ...
Trudne

Zadanie 4: Kalkulator arytmetyki binarnej

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).

Pokaz rozwiazanie
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)
🎥

Materialy wideo

Szybka Powtórka z Ułamków, czyli Lek na Bycie Humanistą
PATOMATMA
Algorytm Euklidesa i liczby pierwsze
Numberphile
🎧

Podcasty

✔️

Quiz - sprawdz sie!

📜

Podstawa programowa

← Lekcja 14: Powtorzenie i sprawdzian Siatka godzinowa