Odpowiedzi:
Nadal można uzyskać wartości inne niż liczba (NaN) z prostej arytmetyki obejmującej inf
:
>>> 0 * float("inf")
nan
Zauważ, że zwykle nie otrzymasz inf
wartości poprzez zwykłe obliczenia arytmetyczne:
>>> 2.0**2
4.0
>>> _**2
16.0
>>> _**2
256.0
>>> _**2
65536.0
>>> _**2
4294967296.0
>>> _**2
1.8446744073709552e+19
>>> _**2
3.4028236692093846e+38
>>> _**2
1.157920892373162e+77
>>> _**2
1.3407807929942597e+154
>>> _**2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
OverflowError: (34, 'Numerical result out of range')
inf
Wartość jest uważane za bardzo szczególny stosunek z niezwykłymi semantyki, więc lepiej wiedzieć o OverflowError
razu przez wyjątek, a nie posiadające inf
wartość cicho wtryskiwanego do swoich obliczeń.
**
wydaje się być trochę powalony . Kiedy przepełnia się liczbami rzeczywistymi, generuje błąd, ale gdy którykolwiek z jego operandów jest inf
lub -inf
, zwraca albo 0.0
albo inf
. Więc to nie działa prawidłowo, jeśli wejście jest inifinty, ale nie wtedy, gdy wynik powinien być nieskończoność.
Implementacja Pythona całkiem dobrze podąża za standardem IEEE-754 , którego można użyć jako przewodnika, ale zależy on od systemu bazowego, na którym został skompilowany, więc mogą wystąpić różnice między platformami . Ostatnio¹ została zastosowana poprawka, która dopuszcza zarówno „nieskończoność”, jak i „inf” , ale ma to niewielkie znaczenie.
Poniższe sekcje odnoszą się równie dobrze do każdego języka, który poprawnie implementuje arytmetykę zmiennoprzecinkową IEEE, nie jest ona specyficzna tylko dla Pythona.
W przypadku operatorów nieskończoności i operatorów większych niż >
lub mniejszych <
liczy się:
+inf
jest wyższa niż-inf
-inf
jest mniejsza niż+inf
+inf
nie jest ani wyższy, ani niższy niż+inf
-inf
nie jest ani wyższy, ani niższy niż -inf
NaN
są fałszywe ( inf
nie są ani wyższe, ani niższe niż NaN
)W porównaniu do równości +inf
i +inf
są równe, tak jak -inf
i -inf
. Jest to bardzo dyskutowana kwestia i może ci się wydawać kontrowersyjna, ale jest w standardzie IEEE i Python zachowuje się w ten sposób.
Oczywiście, +inf
jest nierówny, -inf
a wszystko, w tym i NaN
sam, jest nierówne NaN
.
Większość obliczeń z nieskończonością da nieskończoność, chyba że oba operandy są nieskończonością, gdy podział operacji lub modulo, lub z mnożeniem przez zero, należy pamiętać o kilku szczególnych zasadach:
NaN
0.0
lub -0.0
².NaN
.inf - inf
, wynik jest niezdefiniowany: NaN
;inf - -inf
, wynik jest inf
;-inf - inf
, wynik jest -inf
;-inf - -inf
, wynik jest niezdefiniowany: NaN
.inf + inf
, wynik jest inf
;inf + -inf
, wynik jest niezdefiniowany: NaN
;-inf + inf
, wynik jest niezdefiniowany: NaN
;-inf + -inf
, wynik jest -inf
.math.pow
, pow
lub **
jest trudne, ponieważ nie zachowuje się tak jak powinno. Zgłasza wyjątek przepełnienia, gdy wynik z dwiema liczbami rzeczywistymi jest zbyt wysoki, aby zmieścić liczbę zmiennoprzecinkową o podwójnej precyzji (powinien zwrócić nieskończoność), ale gdy dane wejściowe to inf
lub -inf
, zachowuje się poprawnie i zwraca albo inf
albo 0.0
. Gdy drugim argumentem jest NaN
, zwraca NaN
, chyba że pierwszym argumentem jest 1.0
. Jest więcej problemów, nie wszystkie omówione w dokumentach .math.exp
cierpi na takie same problemy jak math.pow
. Rozwiązaniem tego problemu w przypadku przepełnienia jest użycie kodu podobnego do tego:
try:
res = math.exp(420000)
except OverflowError:
res = float('inf')
Uwaga 1: jako dodatkowe zastrzeżenie, że zgodnie z definicją standardu IEEE, jeśli wynik obliczeń jest niedopełniony lub przepełniony, wynikiem nie będzie błąd niedopełnienia lub przepełnienia, ale dodatnia lub ujemna nieskończoność: 1e308 * 10.0
daje inf
.
Uwaga 2: ponieważ wszelkie obliczenia ze NaN
zwrotami NaN
i wszelkie porównania do NaN
, w tym NaN
samego siebie false
, należy użyć math.isnan
funkcji do ustalenia, czy liczba rzeczywiście jest liczbą NaN
.
Uwaga 3: mimo że Python obsługuje pisanie float('-NaN')
, znak jest ignorowany, ponieważ nie istnieje NaN
wewnętrzny znak . Jeśli się podzielisz -inf / +inf
, wynik jest następujący NaN
: nie -NaN
(nie ma czegoś takiego).
Uwaga 4: staraj się polegać na jednym z powyższych elementów, ponieważ Python opiera się na bibliotece C lub Java, dla której został skompilowany, i nie wszystkie systemy bazowe poprawnie wdrażają to zachowanie. Jeśli chcesz się upewnić, przetestuj nieskończoność przed wykonaniem obliczeń.
¹) Ostatnio oznacza, że od wersji 3.2 .
²) Punkty zmiennoprzecinkowe obsługują zero dodatnie i ujemne, więc: x / float('inf')
zachowuje swój znak i -1 / float('inf')
daje -0.0
, 1 / float(-inf)
daje -0.0
, 1 / float('inf')
daje 0.0
i -1/ float(-inf)
daje 0.0
. Ponadto, 0.0 == -0.0
jesttrue
, trzeba ręcznie sprawdzić znak, jeśli nie ma to być prawdą.
-1 * float('infinity') == -inf
Podobnie C99 .
Reprezentacja zmiennoprzecinkowa IEEE 754 używana przez wszystkie nowoczesne procesory ma kilka specjalnych wzorów bitów zarezerwowanych dla dodatniej nieskończoności (znak = 0, exp = ~ 0, frac = 0), ujemna nieskończoność (znak = 1, exp = ~ 0, frac = 0 ) i wiele NaN (Not a Number: exp = ~ 0, frac ≠ 0).
Wszystko, o co musisz się martwić: pewna arytmetyka może powodować wyjątki / pułapki zmiennoprzecinkowe, ale nie są one ograniczone tylko do tych „interesujących” stałych.
OverflowError
.
Znalazłem zastrzeżenie, o którym nikt dotąd nie wspomniał. Nie wiem, czy będzie się często pojawiał w praktycznych sytuacjach, ale tutaj jest to ze względu na kompletność.
Zwykle obliczenie liczby modulo nieskończoności zwraca się jako liczba zmiennoprzecinkowa, ale ułamek modulo nieskończoności zwraca nan
(nie liczbę). Oto przykład:
>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan
Złożyłem problem w narzędziu do śledzenia błędów w Pythonie. Można to zobaczyć na https://bugs.python.org/issue32968 .
Aktualizacja: zostanie to naprawione w Pythonie 3.8 .
BARDZO ZŁA CAVEAT: Podział przez zero
w 1/x
frakcji, do x = 1e-323
tego jest inf
jednak przy x = 1e-324
lub nieco generujeZeroDivisionError
>>> 1/1e-323
inf
>>> 1/1e-324
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero
więc bądź ostrożny!
1e309
będzie interpretowana jako+inf
i-1e309
będzie interpretowana jako-inf
.