10. hét: számrendszerek, számábrázolás
Czirkos Zoltán · 2024.10.23.
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.
Jelentkeztél pót ZH-ra, ha írnod kell? Ha még nem, tedd meg most, már nem sok idő van hátra!
Adjuk meg az alábbi kifejezésekhez tartozó kifejezésfát, figyelembe véve az operátorok precedenciáját!
6 + 2 * 3
2 * 6 - 5 / 3
a = b + c
t[i + 2] * 3
5 * - 6
5 - * 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.
Í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.
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!
Í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).
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 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?
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.