Python Infinity - jakieś zastrzeżenia?

179

Python ma więc dodatnią i ujemną nieskończoność:

float("inf"), float("-inf")

To wydaje się być rodzajem funkcji, która musi mieć pewne zastrzeżenie. Czy jest coś, o czym powinienem wiedzieć?

Casebash
źródło
25
Zauważ, że stała 1e309będzie interpretowana jako +infi -1e309będzie interpretowana jako -inf.
Chris Taylor

Odpowiedzi:

97

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 infwartoś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')

infWartość jest uważane za bardzo szczególny stosunek z niezwykłymi semantyki, więc lepiej wiedzieć o OverflowErrorrazu przez wyjątek, a nie posiadające infwartość cicho wtryskiwanego do swoich obliczeń.

Greg Hewgill
źródło
8
Proste dodawanie zmiennoprzecinkowe, mnożenie itp. Z radością wygeneruje inf: f = 1.3407807929942597e + 154; f * f => inf. Wydaje się raczej wyjątkiem **, aby podnieść błąd OverflowError.
eregon
@eregon **wydaje się być trochę powalony . Kiedy przepełnia się liczbami rzeczywistymi, generuje błąd, ale gdy którykolwiek z jego operandów jest influb -inf, zwraca albo 0.0albo inf. Więc to nie działa prawidłowo, jeśli wejście jest inifinty, ale nie wtedy, gdy wynik powinien być nieskończoność.
Abel
2
@Abel To nie jest buggy. Przepełnienie oznacza, że ​​liczba jest bardzo duża. Zbyt duży, aby go reprezentować, ale wciąż znacznie mniejszy niż nieskończoność. Umieszczenie nieskończoności w takim miejscu może być przydatne dla obsługi wyjątków dla konkretnej logiki aplikacji, ale ogólnie byłoby niepoprawne dla Pythona.
Lutz Prechelt
6
@Lutz, jeśli pojawia się jako pomnożenie, to nadal jest niespójne zachowanie. Z pewnością duży * duży też nie jest nieskończonością.
Richard Rast
100

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.

Porównanie nierówności

W przypadku operatorów nieskończoności i operatorów większych niż >lub mniejszych <liczy się:

  • dowolna liczba włącznie +infjest wyższa niż-inf
  • dowolna liczba włącznie -infjest mniejsza niż+inf
  • +infnie jest ani wyższy, ani niższy niż+inf
  • -inf nie jest ani wyższy, ani niższy niż -inf
  • wszelkie porównania z tym NaNsą fałszywe ( infnie są ani wyższe, ani niższe niż NaN)

Porównanie dla równości

W porównaniu do równości +infi +infsą równe, tak jak -infi -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, +infjest nierówny, -infa wszystko, w tym i NaNsam, jest nierówne NaN.

Obliczenia z nieskończonością

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:

  • pomnożony przez zero, dla którego wynik jest niezdefiniowany, daje wynik NaN
  • dzieląc dowolną liczbę (oprócz samej nieskończoności) przez nieskończoność, która daje 0.0lub -0.0².
  • dzieląc (w tym modulo) dodatnią lub ujemną nieskończoność przez dodatnią lub ujemną nieskończoność, wynik jest niezdefiniowany, więc NaN.
  • odejmując wyniki mogą być zaskakujące, ale kieruj się zdrowym rozsądkiem :
    • gdy robi inf - inf, wynik jest niezdefiniowany: NaN;
    • kiedy to robi inf - -inf, wynik jest inf;
    • kiedy to robi -inf - inf, wynik jest -inf;
    • gdy robi -inf - -inf, wynik jest niezdefiniowany: NaN.
  • podczas dodawania może być podobnie zaskakujące:
    • kiedy to robi inf + inf, wynik jest inf;
    • gdy robi inf + -inf, wynik jest niezdefiniowany: NaN;
    • gdy robi -inf + inf, wynik jest niezdefiniowany: NaN;
    • kiedy to robi -inf + -inf, wynik jest -inf.
  • za pomocą math.pow, powlub **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 influb -inf, zachowuje się poprawnie i zwraca albo infalbo 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.expcierpi 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')

Notatki

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.0daje inf.

Uwaga 2: ponieważ wszelkie obliczenia ze NaNzwrotami NaNi wszelkie porównania do NaN, w tym NaNsamego siebie false, należy użyć math.isnanfunkcji 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 NaNwewnę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.0i -1/ float(-inf)daje 0.0. Ponadto, 0.0 == -0.0jesttrue , trzeba ręcznie sprawdzić znak, jeśli nie ma to być prawdą.

Abel
źródło
11
Mały nitpick: nie każde obliczenie z nieskończonością daje nieskończoność:-1 * float('infinity') == -inf
Evan Krall
4
Właśnie dlatego powiedziałem, że to mała nitpick. Przez minutę martwiłeś mnie, że znak będzie całkowicie ignorowany podczas pracy z nieskończonością, a ja chciałem wyjaśnić innym ludziom.
Evan Krall,
12
Cóż, prawie: 1 / float ('infinity') == 0,0
Phil
3
@Phil: Chociaż jestem prawie pewien, że starałeś się tylko pokazać, że nie wszystkie obliczenia z inf powodują inf lub NaN, chciałem tylko wyjaśnić innym, którzy mogą czytać komentarze, że 1 / float ('infinity ') == 0,0 jest prawdą; ponieważ, gdy zbliżacie się do nieskończoności, wynik podziału zbliża się do 0. Wiem, że to tylko podstawowy rachunek różniczkowy, ale chciałem mieć pewność, że czytający rozumieją lub przynajmniej mają pojęcie, dlaczego wynik jest taki, jaki jest.
Anthony Pace
1
Mam wrażenie, że ta odpowiedź jest znacznie lepsza niż odpowiedź zaakceptowana.
Christian Herenz,
3

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.

efemeryczny
źródło
1
Więc jeśli moja arytmetyka jest zbyt duża, może stać się inf?
Casebash
@Casebash Nie, spowoduje to OverflowError.
wizzwizz4,
2

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 .

Elias Zamaria
źródło
2

BARDZO ZŁA CAVEAT: Podział przez zero

w 1/xfrakcji, do x = 1e-323tego jest infjednak przy x = 1e-324lub 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!

Seyfi
źródło