Hófehérke és a hét törpe a megszokott módon élik életüket. A törpék naponta eljárnak bányászni és a megszerzett kincseket értékesítik. Sikerült olyan felvásárlókat találniuk, akik hosszútávú fix áras szerződéssel, heti kétszeri fizetéssel biztos havi bevételeket generálnak számukra. Azonban nem hagyatkoznak csak erre, hanem az év során próbálják értékesíteni máshol is a bányászott dolgokat, de ez nem minden nap sikerül, ezért csak kb. az év harmadában jutnak jövedelemhez, de sajnos vannak olyan napok, amikor gyenge a kereslet és ezért önköltség alatt, vagyis veszteséggel tudnak csak megszabadulni a készleteiktől.
A törpék jól értenek a bányászáshoz és alapvetően az értékesítéshez is van érzékük, de a matek nem az erősségük. Az egész számokkal még csak-csak tudnak bánni, de a törtekkel már gondjaik vannak. Ez azért gond, mert az éppen aktuális napi bevételt egyenlően kellene hetük között szétosztani. Ez azonban legtöbbször tört érték. Ezért megkérték Hófehérkét, akit szinte házi bankárjuknak tekintettek, hogy ő tegye meg a bevételek egyenlő módon való elosztását. Hófehérke elég jó matekból, nem gond neki a törtekkel való számolás. Viszont tudja, hogy a törpék csak az egész számokat értik. Ezért miután egy adott napi bevételt elosztott héttel, az eredményt egész számra kell kerekítenie. Igen ám, de nem tudja, hogy hogyan, milyen módszerrel tudná a kerekítést úgy elvégezni, hogy összességében legkevesebb eltérés legyen a kerekített értékek és a kifizetések összege között.
De Hófehérkének e feladat nem okoz nagy problémát, mert míg a törpék napközben bányásztak, addig ő – már csak unaloműzésként is – megtanult Pythonban programozni. Ezért tudja, hogy különböző kerekítési módszereket a szabványos könyvtár decimal moduljával tud vizsgálni és elemezni. Írt is egy erre szolgáló programot, amit alább megosztott velünk. A részletes kommentek segítik a megértését.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
from decimal import * from random import randint # Az aktuális kontextus kikérése. ctx = getcontext() # A decimal modul egyes kerekítési eljárásait azonosító konstansok string értékeinek listába gyűjtése a # későbbi felhasználásuk megkönnyítéséhez. roundings = [rounding_constant_value for rounding_constant_name, rounding_constant_value in globals().items() if rounding_constant_name.startswith('ROUND')] # Havi fix bevételek fix_incomes_monthly = [24.5, 31.5, 38.5, 45.5, 52.5, 59.5, 66.5, 73.5] # Eseti bevételek és a fix havi bevételek együtt képezik az éves bevételeket. incomes_yearly = [randint(-20, 80) for _ in range(100)] + fix_incomes_monthly * 12 # Az egyes bevételi számokat Decimal típusú számokká alakítjuk. dec_incomes = [Decimal(str(n)) for n in incomes_yearly] print('Kerekítési mód\tEltérés összesen\tÁtlageltérés abszolútérték'.expandtabs(4)) # Kiszámítjuk az egy főre eső bevételt egész számra kerekítve az egyes kerekítési eljárásokkal. for rounding_mode in roundings: ctx.prec = 1 ctx.rounding = rounding_mode # Egy főre eső bevételek. incomes_per_capita = [dec_income / Decimal(7) for dec_income in dec_incomes] # Kiszámítjuk, hogy mik a tényleges eltérések a bevételi értékek és a kerekített kifizetések között. # Ehhez a pontosságot visszaállítjuk azért, hogy a különbségképzés és a további számítások eredményei # ne legyenek egy számjegy pontosságúak. ctx.prec = 28 errors = [dec_income - incomes_per_capita * 7 for dec_income, incomes_per_capita in zip(dec_incomes, incomes_per_capita)] # Meghatározzuk az eltérések átlagát. error_avg = sum(errors) / len(errors) # Kiírjuk az eltéréseket és az eltérések átlagának abszolútértékét. print('{}\t{:+}\t{:+.2f}'.format(ctx.rounding, sum(errors), abs(error_avg)).expandtabs(20)) # Egy futtatás eredménye: # Kerekítési mód Eltérés összesen Átlageltérés abszolútérték # ROUND_UP -1994.3 +10.18 # ROUND_DOWN +566.3 +2.88 # ROUND_CEILING -2055.2 +10.49 # ROUND_FLOOR +627.2 +3.20 # ROUND_HALF_UP -203.0 +1.04 # ROUND_HALF_DOWN +385.0 +1.96 # ROUND_HALF_EVEN +49.0 +0.25 # ROUND_05UP +420.0 +2.14 |
Hófehérke azt vizsgálta, hogy az egyes kerekítési módszerek alkalmazása esetén a bevételek és kerekített kifizetések eltérése átlagának abszolútértéke éves szinten mekkora.
A kapott eredményekből egyértelművé vált számára, hogy e tekintetben a ROUND_HALF_EVEN nevű teljesít a legjobban. Ezért el is nevezte ezt bankár kerekítésnek (banker’s rounding), amely elnevezés utána az egész világon elterjedt.
Azt is észrevette, hogy ez a kerekítési mód akkor teljesít nagyon jól átlagos eltérés tekintetében a többi módszerhez képest, ha a kerekítendő értékek között minél több az olyan, ahol a kerekítendő számjegy 5.
Vizsgálatai és következtetése alapján most értette meg, hogy a decimal modul alapértelmezett kontextusa, valamint a beépített round() függvény miért ezt a kerekítési módszert használja.
A decimal modul nagyon sok lehetőséget kínál a nagy pontosságot igénylő számítások végzéséhez különféle kontextus (pl. pontosság, kerekítési módok) alkalmazása mellett, de a decimális aritmetika számábrázolási ismeretei is szükségesek a megértéséhez és hatékony használatához. Ezért csupán a Python hivatalos dokumentációjára támaszkodva nem biztos, hogy egyszerű a megtanulása. Éppen ezért a Python tudásépítés lépésről lépésre című e-könyv egy önálló alfejezetet szán e modulnak, és megpróbálja közérthetően tálalni a tudnivalókat számos példával, ábrával és táblázattal segítve a megértést, beleértve természetesen a kerekítési módszereket is. Mindezzel a „Készétel fogyasztás – a szabványos könyvtár moduljainak használata” fejezet, „Amikor fontos a pontos számítás – decimal modul” alfejezete foglalkozik. A véletlenszámgenerálásról és az alkalmazható egyes eloszlásokról pedig a „A véletlen használatba vétele” alfejezetben olvashatunk részletesen.