Eksperymentowałem z powłoką IDLE Python 3.4.0 i wykonałem poniższy kod.
>>> from decimal import *
>>> getcontext().prec = 500
>>> e = Decimal(2.4)
>>> print(e)
2.399999999999999911182158029987476766109466552734375
Jak widzisz, ustawiam zmienną e
równa dokładnie 2.4, nic więcej, nic mniej. Jednak kiedy drukowałem e
, zamiast drukowania 2.4
lub 2.400000...
, wydrukowało to, co widzisz powyżej. Próbowałem wtedy zmienić getcontext().prec
do 5, i nadal drukowane dokładnie takie same wyniki. Teraz, aby powtórzyć mój eksperyment, przetestowałem go podając liczbę całkowitą, a następnie inną liczbę dziesiętną.
>>> f = Decimal(10)
>>> print(f)
10
>>> g = Decimal(10.1)
>>> print(g)
10.0999999999999996447286321199499070644378662109375
Dziwny ciąg liczb dziesiętnych jest drukowany tylko wtedy, gdy przypiszę niecałkowitą liczbę z klasą dziesiętną. W końcu przetestowałem to z liczbami zmiennoprzecinkowymi.
>>> h = float(2.4)
>>> print(h)
2.4
>>> i = float(10.1)
>>> print(i)
10.1
Dlaczego klasa dziesiętna powoduje te dziwne ciągi liczb dziesiętnych zamiast dokładnej liczby?
Odpowiedzi:
1 dla odpowiedzi № 1Nie musi to mieć nic wspólnego z Pythonem, jest to po prostu sposób, w jaki komputery obsługują arytmetykę zmiennoprzecinkową.
Udawaj, że próbujesz dokładnie zapisać 1/3jako dziesiętne w podstawie 10 - nie możesz mieć nieskończonej ilości czasu lub papieru. (0.333333 ...) Istnieje nieskończona liczba 3s, więc każda reprezentacja dziesiętna może być jedynie przybliżeniem.
Podobnie, komputery nie mogą reprezentować niektórychfrakcje z doskonałą precyzją. (ponieważ nie mają nieskończonej pamięci), więc w tym przypadku najbliższy komputer może dostać się do 10.1 to 10.0999999999999996447286321199499070644378662109375. Nie ma to związku z getcontext()
lub jakikolwiek inny, ponieważ komputer nie może przechowywać dokładnie 10,1 lub 2.4.
2 dla odpowiedzi nr 2
Kiedy przejdziesz literał 2.4
do dziesiętnego, tworzysz Decimal
z pływaka 2.4. Wartość float jest już przybliżona i nie ma takiej możliwości Decimal
aby odzyskać tę "dokładność".
Aby utworzyć dokładnie dziesiętny (2.4), możesz zamiast tego podać ciąg znaków
>>> from decimal import *
>>> getcontext().prec = 500
>>> e = Decimal("2.4")
>>> e
Decimal("2.4")
lub użyj podziału na wartości dziesiętnej uzyskanej z liczby całkowitej
>>> Decimal(24)/10
Decimal("2.4")