Mint azt a matematikából tudjuk, az irracionális számok mindig végtelen, nem szakaszos tizedestörtként fejezhetők ki, ezért a velük való konkrét numerikus számítások esetén sohasem lehet egzakt eredményt kapni, hanem csak valamilyen pontossággal. Ahhoz, hogy az eredmény pontossága növekedjen az irracionális szám tizedesjegyeinek egyre hosszabb sorozatának meghatározása szükséges. Akkor van gond, ha többször tíz, vagy esetleg több száz tizedesjegyre van igény. Ilyenkor ugyanis a float típusú számok, a bináris számábrázolásuk korlátai következtében, az ilyen nagy pontosságot nem tudják biztosítani. Ekkor lesz segítségünkre a szabványos könyvtár decimal modulja.
Most két irracionális szám közelítő értékét fogjuk meghatározni 500 számjegy pontossággal. Az egyik szám a természetes logaritmus alapszáma, vagy más néven Euler-féle szám, a másik a négyzetgyök kettő. A számításhoz használt képleteket a következők:

Ezeket implementáló függvények definíciója alább látható. Ezekben már Decimal típusú számokkal dolgozunk.
|
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 |
from decimal import Decimal, localcontext E_600 = """2.71828182845904523536028747135266249775724709369995957496696762772407663035354759457138217852\ 516642742746639193200305992181741359662904357290033429526059563073813232862794349076323382988075319525101\ 901157383418793070215408914993488416750924476146066808226480016847741185374234544243710753907774499206955\ 170276183860626133138458300075204493382656029760673711320070932870912744374704723069697720931014169283681\ 902551510865746377211125238978442505695369677078544996996794686445490598793163688923009879312773617821542\ 499922957635148220826989519366803318252886939849646510582093923982948879332036250944311""" SQRT2_600 = """1.4142135623730950488016887242096980785696718753769480731766797379907324784621070388503875\ 343276415727350138462309122970249248360558507372126441214970999358314132226659275055927557999505011527820\ 605714701095599716059702745345968620147285174186408891986095523292304843087143214508397626036279952514079\ 896872533965463318088296406206152583523950547457502877599617298355752203375318570113543746034084988471603\ 868999706990048150305440277903164542478230684929369186215805784631115966687130130156185689872372352885092\ 6486124949771542183342042856860601468247207714358548741556570696776537202264854470158588016""" def e_dec(n): """Az Euler-féle szám közelítő értékét adja vissza. A pontosság az argumentumban megadott egész szám növelésével nő. """ return (Decimal(1) + Decimal(1) / Decimal(n)) ** Decimal(n) def sqrt2_dec(n): """A négyzetgyök 2 közelítő értékét adja vissza. A pontosság az argumentumban megadott egész szám növelésével nő. """ y = Decimal(1) for _ in range(n): y = (y + (Decimal(2) / y)) / Decimal(2) return y |
Ahhoz, hogy ellenőrizzük a számítások helyességét, a fenti kód felső részében minkét szám 600 számjegyet tartalmazó értékét tüntettük fel egy-egy konstansként. Ezeket megtalálhatjuk az interneten keresve.
Az ellenőrzést úgy tesszük meg, hogy megvizsgáljuk, hogy az általunk számított érték karakterlánc formájában milyen hosszú karaktersorozat egyezik meg a 600 karaktert tartalmazó konstansokkal. Ez az ellenőrző függvény a következő:
|
1 2 3 4 5 6 7 8 9 10 11 |
def num_of_first_matching_chars(s1, s2): """Visszaadja, hogy az argumentumok mint sorzatok első hány eleme egyezik meg.""" match = 0 for t in zip(s1, s2): if len(set(t)) == len(t): return match else: match += 1 return match |
Azt, hogy mi a két szám közelítő képlete esetében a legkevesebb számítási igény, ami legalább 500 jegy pontosságot biztosít, egy alább látható függvénnyel határozzuk meg. Ennek működése a részletes kommentekből megérthető.
|
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 |
def approx(func, num_of_digits: int): """Visszatérési értéke a közelítendő szám értéke num_of_digits számjegy pontossággal, ahol a func fogadja a közelítő érték számítását tartalmazó függvényt. """ with localcontext() as ctx: # A decimális aritmetika kontextusának pontosságát az aktuálisan elvárt pontossághoz igazítjuk. # Kicsit többet adunk meg a kerekítések befolyásánka csökkentésére. ctx.prec = num_of_digits + 5 n = 10 c = 10 while True: # Az aktuális n értékkel kiszámolunk egy közelítő értéket. estimate1 = func(n) # Az aktuális n érték c szeresével is kiszámolunk egy újabb közelítő értéket. estimate2 = func(n * c) # Mivel n*c nagyobb, mint n, ezért a második közelítés több jegyre lesz pontosabb mint az előző. # Ha a két közelítő érték egyező tizedesjegyei nem érték még el a kíván hosszt, akkor # a második becslést tekintjük új alapnak, majd növeljük a n-t, c-szeresre, és megismételjük a számítást. if num_of_first_matching_chars(str(estimate1), str(estimate2)) >= num_of_digits+1: approx.n = Decimal(n) # A végső n értéket mint kiegészítő információt függvényattribútumban tároljuk. return estimate2 # Az elvárt pontosságú közelítő értékkel térünk vissza. n *= c |
A közelítő számításokat és azok eredményét a következő sorok mutatják. Itt azt is megfigyelhetjük, hogy a négyzetgyök számítási képlete sokkal gyorsabban konvergál, mint az Euler számé.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# TESZT matching_decimals = 500 # Legalább ennyi számjegy pontossággal akarjuk a közelítő értéket megkapni. print(f'Az Euler-féle szám közelítő értékének számítása legalább {matching_decimals} számjegy pontossággal.') approximation = approx(e_dec, matching_decimals) # A számolt közelítő érték. Nem írjuk ki mert hosszú lenne. print('Aktuális pontosság: {}, n: {:.1e}'.format(num_of_first_matching_chars(E_600, str(approximation)), approx.n)) print(f'A négyzetgyök 2 közelítő értékének számítása legalább {matching_decimals} számjegy pontossággal.') approximation = approx(sqrt2_dec, matching_decimals) # A számolt közelítő érték. Nem írjuk ki mert hosszú lenne. print('Aktuális pontosság: {}, n: {:.1e}'.format(num_of_first_matching_chars(SQRT2_600, str(approximation)), approx.n)) # Eredmények: # Az Euler-féle szám közelítő értékének számítása legalább 500 számjegy pontossággal. # Aktuális pontosság: 502, n: 1.0e+500 # A négyzetgyök 2 közelítő értékének számítása legalább 500 számjegy pontossággal. # Aktuális pontosság: 506, n: 1.0e+1 |
Mindezek után esetleg felmerülhet, hogy vajon szükség van-e egyáltalán több száz számjegy pontosságú számításra.
Azt, hogy több száz, vagy csak több tíz számjegy pontosság szükséges, az nyilván alkalmazásfüggő. Mindenesetre vannak olyan használati esetek, amelyek igen nagy pontosságú számításokat igényelnek. Többek között ilyen például az űrkutatás, űrhajózás, ahol a nagy távolságok miatt a pályaszámításoknak nagyon pontosaknak kell lenni. Ennek fontosságát láthatjuk a megtörtént események alapján készült „A számolás joga” (eredetileg: Hidden Figures) című filmben, ami a Mercury űrprogramról szól, és a középpontjában az a három matematikus nő (Katherine Johnson, Dorothy Vaughan és Mary Jackson) áll, akik kézzel végezték a pályaszámításokat. Azt nem tudni, hogy van-e összefüggés a számított tizedesjegyek hossza és az életkor között, de az biztos, hogy a három hölgy igen magas kort ért meg (101, 98 és 83).
A nagy pontosságú számításokhoz a Python szabványos könyvtár decimal modulja nélkülözhetetlen. A használatának megértése azonban csupán a Python hivatalos dokumentáció alapján nem biztos, hogy mindenki számára egyszerű. 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. 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.