Skip to main content
  1. Posts/
  2. blog.dsinf.net/

Duże liczby w Pythonie

·431 words·3 mins
blog.dsinf.net python
Daniel Skowroński
Author
Daniel Skowroński

Python jest językiem wyjątkowym. Jednym z reprezentantów tej wyjątkowości jest sposób przechowywania dużych liczb.

Liczby zmiennopozycyjne Python przechowuje jak każdy inny język - cecha i mantysa. Dla liczb liczb całkowitych stosowany jest całkowicie inny sposób przechowywania. Jeżli liczba mieści się w zakresie sys.maxint (czyli 2**63-1 lub 2**31-1 w zależności od bitowości instalacji Pythona) to wszystko jest jak w “normalnych” środowiskach C-podobnych. Jednak po czymś w rodzaju “inta” nie ma “longa” tylko bardziej “BigInteger”.

Kiedy wykorzystujemy środowisko do obliczeń wypada poznać zakres i dokładność dostępnych struktu liczbowych.
Najprostszy pomiar dokładności polega na sprawdzaniu kolejnych potęg 10 na wrażliwość na dodanie jakiejś małej wartości, która nas interesuje - będzie to miara dokładności - dla zmiennoprzecinkowych weźmiemy celem przykładu 0.1, a całkowitych najmniejszą możliwą - 1. (Można zapytać po co sprawdzać dokładność inta - chcemy zapobiec typowego dla środowisk skryptowych cichego zrzutowania na typ inny niż integer np. double)

W pętli wystarczy teraz mnożyć liczbę razy 10 i porównać wartość zmiennej liczba i (liczba+encjaTestowa). Przykładowy kod w języku, który rozważamy wygląda następująco:

def czyDokladneFloat(liczba):
	liczba1 = float(liczba)
	liczba2 = float(liczba+0.1)
	return ( float(liczba1) < float(liczba2) )
def czyDokladneInt(liczba):
	liczba1 = int(liczba)
	liczba2 = int(liczba+1)
	return ( int(liczba1) < int(liczba2) )

licznik = 1
dokladna = True
print("Sprawdzam zmiennoprzecinkowe:")
while dokladna:
	liczba = 10**licznik
	dokladna = czyDokladneFloat(liczba)
	print ("10^"+str(licznik)+": "+("NIE" if not dokladna)+"dokładna")
	licznik+=1

licznik = 1
dokladna = True
print("Sprawdzam stałopozycyjne:")
while dokladna:
	liczba = 10**licznik
	dokladna = czyDokladneInt(liczba)
	print ("10^"+str(licznik)+": "+("NIE" if not dokladna)+"dokładna")
	licznik+=100 #+=100 bo inaczej idzie strasznie powoli

Castowanie w funkcjach wymusza użycie tego konkretnie typu bez “sprytnych” konwersji i ewentualnych operacji na łańcuchach znaków.

Co się okazuje? Maksymalna wartość float’a dokładnego do 0.1 to 10^16 (podobnie jak w typowych językach kompilowanych i skryptowych), a dla 1 w integerach… jest nieskończona. To znaczy jak poczekamy odpowiednio długo skończy nam się pamięć.

Oczywiście w językach/środowiskach, które zapewniają rozróżnienie na liczby ze znakiem i w wyniku przepelnienia “przekręcają się” dając dla MAX+1 wartość MIN należy implementując powyższe testy pamiętać o ograniczeniu pętli do liczb dodatnich.

W ogólności dokładność Integera w Pythonie 3 to stała = 1. Tak też jest w językach niższego poziomu. Jednak wysokopoziomowe środowiska mogą stosować rzutowanie na różne dziwne struktury i niekoniecznie rozwróżniać gogol od (gogol+1).

Wiedza o obsłudze ogromnych (>10**30) liczb calkowitych pozwala np. generować dane do stablicowania. W Pythonie można się nawet pokusić o osłonienie liczb zmiennoprzecinkowych jako klasy składającej się z Int liczba i Int dokładność - potęga dziesiątki. Umożliwia to prawie nieskończoną dokładność tak cenną w wielu projektach pomocniczych przy jednocześnie niskim koszcie implementacji (zamiast tworzenia własnych struktur w C++ wystarczy jeden skrypt w Pythonie).