11. hét: számrendszerek, számábrázolás
Czirkos Zoltán · 2025.11.14.
A számrendszerekről szóló előadáshoz kapcsolódó feladatok. Néhány számábrázolási probléma megjelenése a programokban.
Felkészülés a laborra:
- Az operátorokról tanultak átismétlése.
- A számábrázolásról, számrendszerekről tanultak megértése.
Adjuk meg az alábbi kifejezésekhez tartozó kifejezésfát, figyelembe véve az operátorok precedenciáját!
6 + 2 * 32 * 6 - 5 / 3a = b + ct[i + 2] * 35 * - 65 - * 6
A legegyszerűbb ascii karakterekkel megrajzolni és úgy feltölteni. Ebben a feladatban nem kell kódolni, csak rajzolni.
Kétszer kettő: * / \ 2 2
Megoldás
Mit írnak ki az alábbi program egyes sorai? Próbáld meg kitalálni! Futtasd le a programot, és magyarázd meg az eredményt!
print("1.", 1e200 / 1e-200)
print("2.", "igaz" if 1e3 + 1 == 1e3 else "hamis")
print("3.", "igaz" if 1e30 + 1 == 1e30 else "hamis")
Megoldás
Az 1-eshez: 10200/10-200 = 10400 lenne. De ez már nem fér bele a float
típus ábrázolási tartományába, ezért végtelent kapunk.
Az 2-es és 3-as sorhoz: míg a 103+1 értéke különbözik 103-től, mivel a két szám, 1000 és 1 nem tér el túlzottan egymástól nagyságrendben. A 1030 és 1 esetén ez már nem igaz.
Az alábbi program egy színátmenetes rajzot hivatott elkészíteni. A színek balról jobbra egyre pirosabbak, és alulról felfelé egyre kékebbek. A színkomponensek értéke mindig 0-tól 1-ig változik. Az osztások számát a program a felhasználótól kéri, az egyes kis négyzetek oldalhossza 30 képpont.
A program némely osztásszámra kifogástalanul működik, például db = 5-re a képen látható ábrát
készíti. Más osztások esetén elromlik, db = 10 esetén szétcsúszik az ábra.
Mi a probléma? Magyarázd meg a jelenséget, és mutasd meg a nyomkövetőben is! Javítsd meg a programot, hogy minden osztásszámra helyesen működjön!
import turtle
def negyzet(a):
turtle.begin_fill()
for i in range(0, 4):
turtle.forward(a)
turtle.left(90)
turtle.end_fill()
def main():
a = 30 # oldalhossz
db = int(input("Hány darabból? "))
turtle.speed(0)
b = 0.0
while b <= 1.0:
r = 0.0
while r <= 1.0:
turtle.fillcolor(r, 0, b)
negyzet(a)
turtle.forward(a)
r += 1/(db-1)
turtle.backward(db*a)
turtle.left(90)
turtle.forward(a)
turtle.right(90)
b += 1/(db-1)
turtle.done()
main()
Megoldás
A lebegőpontos számítás pontatlansága. Az alábbi programocska jól mutatja a problémát db = 10 esetén:
db = 10
egesz = 0
valos = 0.0
while egesz <= db:
print(egesz, valos)
egesz += 1
valos += 1 / (db-1)
Nem szabad float változóra építeni a ciklust, ha tudni akarjuk, hogy pontosan hányszor fut a törzse.
Márpedig itt igen, mert pontosan 10 darab négyzetet kell rajzolni, nem 11-et vagy 9-et valamiféle kerekítési/számítási
hiba miatt.
def javitott():
a = 30 # oldalhossz
db = int(input("Hány darabból? "))
turtle.speed(0)
for b in range(db):
for r in range(db):
turtle.fillcolor(r/(db-1), 0, b/(db-1))
turtle.begin_fill()
negyzet(a)
turtle.forward(a)
turtle.backward(db*a)
turtle.left(90)
turtle.forward(a)
turtle.right(90)
turtle.done()
Írj programot, amelyik a megadott számot a megadott számrendszerbe alakítja át, és beteszi úgy egy sztringbe! Pl. a 9-es szám
2-es számrendszerben "1001". Az algoritmusod tetszőleges lehet, de a végén egy print(szam) utasítással
ki kell tudni írni a számot, ahol a szam annak a változónak a neve, amiben az eredményt előállítottad.
Elég, ha előbb csak tízes számrendszerig működik a program! Ha működik jól a programod, akkor utána alakítsd át úgy, hogy nagyobb alap esetén is működjön! A 10-et, és annál nagyobb számjegyeket ilyenkor betűkkel szokás jelölni. Pl. 16-osban a 0…15 számjegyek: 012…89ABCDEF.
Tipp
Az alapötlet az, hogy maradékképzéssel látod a szám legutolsó számjegyét, utána pedig egész osztással le tudod vágni azt az utolsó számjegyet, amit kezeltél.
| Szám | %10 | //10 |
|---|---|---|
| 1234 | 4 | 123 |
| 123 | 3 | 12 |
| 12 | 2 | 1 |
| 1 | 1 | 0 |
Megoldás
Az alsó számjegy meghatározása által mindig a legutolsó számjegyet kapjuk, vagyis fordított sorrendben állnak elő az adatok. A sorrend megfordítását sokféleképpen megoldhatjuk: például mindig a sztring elé fűzünk, esetleg mindig a végére, és a végeredményt fordítjuk meg, vagy használhatunk akár rekurziót is.
def atalakit(szam, szamrendszer):
# iteratív változat, csak pozitív számokra és 2-16 közötti számrendszerekre, nullára nem működik...
szamjegyek = "0123456789ABCDEF"
szamstr=""
while szam > 0:
maradek = szam % szamrendszer
szamstr = szamjegyek[maradek]+ szamstr
szam = szam // szamrendszer
return szamstr
# rekurzív változat, csak pozitív számokra és 2-16 közötti számrendszerekre, nullára nem működik...
def atalakit_rekurziv(szam, szamrendszer):
szamjegyek = "0123456789ABCDEF"
if szam == 0:
return ""
else:
return atalakit_rekurziv(szam // szamrendszer, szamrendszer) + szamjegyek[szam % szamrendszer]
Működik az előző feladatban megírt programod 0-ra is? Az algoritmustól függően előfordulhat, hogy 0-ra üres sztringet ad. Ha ilyen megoldást adtál, akkor egészítsd ki!
Oldd meg továbbá azt, hogy negatív számot is kaphasson! A pozitív számokat nem kell plusszal jelölni, a negatívak elé viszont kerüljön mínusz karakter!
Megoldás
# valójában hátultesztelő ciklikus kellene, de ezt csak szimulálni tudjuk Pythonban
def atalakit(szam, szamrendszer):
szamstr=""
if szam < 0:
szam = -szam
elojel = "-"
else:
elojel = ""
while True:
szamjegy = szam % szamrendszer
karakter= chr( ord('0') + szamjegy if szamjegy < 10 else ord('A') + (szamjegy - 10))
szamstr = karakter + szamstr
szam = szam // szamrendszer
if szam == 0:
break
return elojel + szamstr
Írj programot, amely kap egy sztringet és egy számrendszernek a számát, majd megadja azt az egész számot, amit az adott sztringbeli számjegysorozat reprezentál! Például ha a felhasználó beírja, hogy 2-es számrendszer, és 1101, akkor ki kell írni, hogy 13. Először elég, ha tízes számrendszerig működik a program, csak utána írd át úgy, hogy működjön nagyobb alap esetén is!
Hányas számrendszerben fogsz írni? 16 Ird be a szamot! fce2 A beolvasott szám 10-es számrendszerben: 64738
Ha elkészültél a saját algoritmussal, ellenőrizd különféle számokra a beépített konverzióval! Pl. int("fce2", 16)
a fenti példa alapján 64738-at ad.
Tipp
Ehhez végig kell haladni a sztringen, és a meglévő adathoz (megszorozva persze az alappal) mindig hozzáadható az új érték:
| Eddig megvolt | Új számjegy | Új érték |
|---|---|---|
| 0 | 1 | 1 |
| 1 | 2 | 12 |
| 12 | 3 | 123 |
| 123 | 4 | 1234 |
Megoldás
Megoldási terv, ötletek
- Beolvasunk egy számjegyet (karaktert), és kivonjuk belőle a
'0'karakterkódját. Így megkapjuk az értékét. - Hogy lesz egy számjegyből sok? Pl. 123 esetén, ha a 12-t már beolvastuk, és jön még egy 3-as, akkor a 12 igazából a 120-at jelentette (megszorozzuk 10-szel), és ahhoz adjuk a 3-at. Ha 123 esetén 4-es jön, akkor igazából 1230 volt, és ahhoz adjuk a 4-et.
- Vagyis mindig az eddigi, szorozva 10-zel (a számrendszer alapjával), plusz az új számjegy.
Az egyszerű számításhoz felhasználhatjuk a Horner-elrendezést. Vegyük példának ehhez 10-es számrendszerben
a 234-et! Ezt az egyes számjegyekből 2×102+3×101+4×100 formában
határozhatjuk meg. Ami pedig ugyanaz, mint ((2×10)+3)×10+4, azaz (((0×10+2)×10)+3)×10+4,
amiből már látszik, hogyan kell dolgoznunk: mindig a meglévő részeredményt megszoroznunk tízzel, és hozzáadni az
új számjegy értékét. Ha eddig a 23-at láttuk, és megkapjuk a 4-est, akkor a szóban forgó lépés 23×10+4 = 230+4
lesz. Ezt kell folytatni egészen addig, amíg határoló karaktert nem kapunk, persze a tízzel szorzás helyett az
adott számrendszer alapját tekintve.
A számjegy beolvasásánál figyelembe kell venni, hogy bár számjegyről beszélünk, tízes számrendszer fölött
ez lehet betű is. Ezért a beolvasott karaktert meg kell vizsgálni, számjegyről van-e szó (0...9) vagy betűről (a...z).
Ha számjegyről, akkor a '0'-s számjegy karakterkódját kell kivonni belőle, hogy számértéket kapjunk, amúgy pedig az
'a' betű karakterkódját, és hozzáadni 10-et, mert A=10, B=11 stb. Itt kapóra
jönnek a sztring típus függvényei: .isdigit() = számjegy-e?, .isalpha() = betű-e?,
.upper() = a karakter nagybetűként (ha szépen szeretnénk csinálni).
def beolvas(szoveg, szamrendszer):
szam = 0
for karakter in szoveg:
if karakter.isdigit():
ertek = ord(karakter) - ord('0')
else:
ertek = ord(karakter.upper()) - ord('A') + 10
szam = szam * szamrendszer + ertek
return szam
Dolgozd át úgy az előző feladatok „kiírás adott számrendszerben” és „beolvasás adott számrendszerben” programkódjait, hogy azok függvények legyenek! Például:
szamrendszerbol("fce2", 16)→64738.szamrendszerbe(64738, 16)→"FCE2".
Készítsd fel a függvényeket hibák kezelésére! Pl. ha adott számrendszerben nem létezik egy számjegy, akkor dobjon kivételt az első függvény. Ha negatív, vagy nullás/egyes számrendszerbe átalakítást kérünk, akkor dobjon kivételt a második, és így tovább. Milyen hibalehetőségek lehetnek még?
Megoldás
# végleges megoldások hibakezeléssel 26 karakterig megyünk, max 36-os számrendszer engedélyezett
def szamrendszerbol(szoveg, szamrendszer):
# átadott paraméterek ellenőrzése
if len(szoveg) == 0:
raise ValueError("A szöveg nem lehet üres!")
if szamrendszer < 2 or szamrendszer > 36:
raise ValueError("A számrendszer 2 és 36 között kell, hogy legyen!")
negativ=False
if szoveg[0] == '-':
negativ = True
szoveg = szoveg[1:]
elif szoveg[0] == '+':
szoveg = szoveg[1:]
if len(szoveg) == 0:
raise ValueError("Csak előjelet tartalmay!")
szam = 0
for karakter in szoveg:
if karakter.isdigit():
ertek = ord(karakter) - ord('0')
elif karakter.upper().isalpha():
ertek = ord(karakter.upper()) - ord('A') + 10
else:
raise ValueError(f"Érvénytelen karakter: {karakter}")
if ertek >= szamrendszer:
raise ValueError(f"A(z) {karakter} nem érvényes a {szamrendszer}-es számrendszerben!")
szam = szam * szamrendszer + ertek
if negativ:
szam = -szam
return szam
def szamrendszerbe(szam, szamrendszer):
# átadott paraméterek ellenőrzése
if szamrendszer < 2 or szamrendszer > 36:
raise ValueError("A számrendszer 2 és 36 között kell, hogy legyen!")
szamstr=""
if szam < 0:
szam = -szam
elojel = "-"
else:
elojel = ""
while True:
szamjegy= szam % szamrendszer
szamstr = ((chr( ord('0')+szamjegy)) if szamjegy < 10 else chr( ord('A')+szamjegy-10)) + szamstr
szam = szam // szamrendszer
if szam == 0:
break
return elojel + szamstr
Ha a laborfeladatokkal elkészültél, dolgozz a példatárban lévő feladatokon, a szorgalmi feladatokon, a minta vizsgán, vagy a házi feladatodon.
Informatikusok próbálják lekódolni az Algoritmusok és gráfok tárgyon tanult algoritmusokat. Ezzel két legyet lehet ütni egy csapásra, mert két tantárgyat is gyakoroltok egyszerre.