Python Infinity - Vorbehalte?

178

Python hat also eine positive und eine negative Unendlichkeit:

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

Dies scheint nur die Art von Funktion zu sein, die einige Einschränkungen aufweisen muss. Gibt es etwas, das ich beachten sollte?

Casebash
quelle
25
Beachten Sie, dass die Konstante 1e309als interpretiert wird +infund -1e309als interpretiert wird -inf.
Chris Taylor

Antworten:

97

Sie können immer noch NaN-Werte (Not-a-Number) durch einfache Arithmetik erhalten, die Folgendes umfasst inf:

>>> 0 * float("inf")
nan

Beachten Sie, dass Sie in der Regel nicht eine bekommen infWert durch übliche arithmetische Berechnungen:

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

Der infWert wird als ein ganz besonderer Wert mit ungewöhnlicher Semantik betrachtet. Es ist daher besser, OverflowErrorsofort über eine Ausnahme Bescheid zu wissen , als einen infWert stillschweigend in Ihre Berechnungen einfließen zu lassen.

Greg Hewgill
quelle
8
Eine einfache Float-Addition, Multiplikation usw. erzeugt jedoch glücklich inf: f = 1.3407807929942597e + 154; f * f => inf. Es scheint eher eine Ausnahme von ** zu sein, einen OverflowError auszulösen.
Eregon
@eregon **scheint eigentlich ein bisschen fehlerhaft . Wenn es mit reellen Zahlen überläuft, gibt es einen Fehler aus, aber wenn einer seiner Operanden infoder ist -inf, gibt es entweder 0.0oder zurück inf. Es funktioniert also korrekt, wenn die Eingabe unendlich ist, aber nicht, wenn das Ergebnis unendlich sein sollte.
Abel
2
@Abel Das ist kein Buggy. Überlaufen bedeutet, dass die Anzahl sehr groß ist. Zu groß, um es darzustellen, aber immer noch viel kleiner als unendlich. Das Platzieren von unendlich an einem solchen Ort kann für den Ausnahmebehandler Ihrer speziellen Anwendungslogik nützlich sein, wäre jedoch für Python im Allgemeinen falsch.
Lutz Prechelt
6
@Lutz Wenn es dann als Multiplikation auftaucht, ist es immer noch inkonsistentes Verhalten. Sicherlich ist groß * groß auch nicht unendlich.
Richard Rast
100

Die Implementierung von Python folgt ziemlich gut dem IEEE-754-Standard , den Sie als Richtlinie verwenden können, basiert jedoch auf dem zugrunde liegenden System, auf dem es kompiliert wurde, sodass Plattformunterschiede auftreten können. Kürzlich¹ wurde ein Fix angewendet, der sowohl "unendlich" als auch "inf" zulässt , aber das ist hier von untergeordneter Bedeutung.

Die folgenden Abschnitte gelten gleichermaßen für jede Sprache, die IEEE-Gleitkomma-Arithmetik korrekt implementiert. Sie ist nicht nur für Python spezifisch.

Vergleich für Ungleichheit

Beim Umgang mit unendlich und Operatoren, die größer >oder kleiner als <sind, zählt Folgendes:

  • Jede Zahl einschließlich +infist höher als-inf
  • Jede Zahl einschließlich -infist niedriger als+inf
  • +infist weder höher noch niedriger als+inf
  • -inf ist weder höher noch niedriger als -inf
  • Jeder Vergleich NaNist falsch ( infweder höher noch niedriger als NaN)

Vergleich für Gleichheit

Im Vergleich zur Gleichheit +infund +infsind gleich, wie -infund -inf. Dies ist ein viel diskutiertes Thema und mag für Sie kontrovers klingen, aber es ist im IEEE-Standard und Python verhält sich einfach so.

Natürlich +infist ungleich -infund alles, einschließlich sich NaNselbst, ist ungleich NaN.

Berechnungen mit unendlich

Die meisten Berechnungen mit unendlich ergeben unendlich, es sei denn, beide Operanden sind unendlich, wenn die Operation Division oder Modulo oder bei Multiplikation mit Null einige spezielle Regeln zu beachten sind:

  • Wenn es mit Null multipliziert wird, für das das Ergebnis undefiniert ist, ergibt es NaN
  • wenn eine beliebige Zahl (außer unendlich selbst) durch unendlich geteilt wird, was ergibt 0.0oder -0.0².
  • Wenn die positive oder negative Unendlichkeit durch positive oder negative Unendlichkeit geteilt wird (einschließlich Modulo), ist das Ergebnis undefiniert NaN.
  • Beim Subtrahieren mögen die Ergebnisse überraschend sein, folgen aber dem gesunden Menschenverstand :
    • dabei inf - infist das Ergebnis undefiniert : NaN;
    • wenn Sie dies tun inf - -inf, ist das Ergebnis inf;
    • wenn Sie dies tun -inf - inf, ist das Ergebnis -inf;
    • Dabei -inf - -infist das Ergebnis undefiniert : NaN.
  • Beim Hinzufügen kann es auch ähnlich überraschend sein:
    • wenn Sie dies tun inf + inf, ist das Ergebnis inf;
    • dabei inf + -infist das Ergebnis undefiniert : NaN;
    • dabei -inf + infist das Ergebnis undefiniert : NaN;
    • Wenn Sie dies tun -inf + -inf, ist das Ergebnis -inf.
  • mit math.pow, powoder **ist schwierig, da es nicht benimmt , wie es sollte. Es wird eine Überlaufausnahme ausgelöst, wenn das Ergebnis mit zwei reellen Zahlen zu hoch ist, um auf einen Float mit doppelter Genauigkeit zu passen (es sollte unendlich zurückgeben), aber wenn die Eingabe infoder ist -inf, verhält es sich korrekt und gibt entweder infoder zurück 0.0. Wenn das zweite Argument ist NaN, wird es zurückgegeben NaN, es sei denn, das erste Argument ist 1.0. Es gibt weitere Probleme, die nicht alle in den Dokumenten behandelt werden .
  • math.expleidet die gleichen Probleme wie math.pow. Eine Lösung, um dies für einen Überlauf zu beheben, besteht darin, ähnlichen Code zu verwenden:

    try:
        res = math.exp(420000)
    except OverflowError:
        res = float('inf')

Anmerkungen

Anmerkung 1: Als zusätzliche Einschränkung, die gemäß IEEE-Standard definiert ist, ist das Ergebnis, wenn Ihr Berechnungsergebnis unter- oder überläuft, kein Unter- oder Überlauffehler, sondern eine positive oder negative Unendlichkeit: 1e308 * 10.0Ausbeute inf.

Hinweis 2: Da jede Berechnung mit NaNRückgaben NaNund jeder Vergleich mit NaN, einschließlich sich NaNselbst, erfolgt false, sollten Sie die math.isnanFunktion verwenden, um festzustellen, ob eine Zahl tatsächlich ist NaN.

Hinweis 3: Obwohl Python das Schreiben unterstützt float('-NaN'), wird das Zeichen ignoriert, da NaNintern kein Anmelden vorhanden ist . Wenn Sie teilen -inf / +inf, ist das Ergebnis NaNnicht -NaN(so etwas gibt es nicht).

Hinweis 4: Achten Sie darauf, dass Sie sich auf die oben genannten Punkte verlassen, da Python auf der C- oder Java-Bibliothek basiert, für die es kompiliert wurde, und nicht alle zugrunde liegenden Systeme dieses Verhalten korrekt implementieren. Wenn Sie sicher sein möchten, testen Sie vor den Berechnungen auf Unendlich.

¹) In letzter Zeit bedeutet seit Version 3.2 .
²) Gleitkommazahlen unterstützen positive und negative Nullen, also: x / float('inf')behält Vorzeichen und -1 / float('inf')Renditen -0.0, 1 / float(-inf)Renditen -0.0, 1 / float('inf')Renditen 0.0und -1/ float(-inf)Renditen 0.0. Darüber hinaus 0.0 == -0.0isttrue , müssen Sie manuell die Zeichen , wenn Sie es wahr sein nicht wollen.

Abel
quelle
11
Ein kleiner Trottel: Nicht jede Berechnung mit unendlich ergibt unendlich:-1 * float('infinity') == -inf
Evan Krall
4
Deshalb habe ich gesagt, es sei ein kleiner Trottel. Sie hatten mir eine Minute lang Sorgen gemacht, dass das Zeichen bei der Arbeit mit der Unendlichkeit völlig ignoriert würde, und ich wollte es anderen Menschen klarstellen.
Evan Krall
12
Na ja, fast: 1 / float ('unendlich') == 0.0
Phil
3
@Phil: Obwohl ich mir ziemlich sicher bin, dass Sie nur versucht haben zu zeigen, dass nicht alle Berechnungen mit inf zu inf oder NaN führen, wollte ich nur anderen klar machen, die möglicherweise die Kommentare lesen, dass 1 / float ('unendlich) ') == 0.0 ist wahr; Wenn Sie sich der Unendlichkeit nähern, nähert sich das Ergebnis der Division 0. Ich weiß, es ist nur eine Grundrechnung, aber ich wollte sichergehen, dass die Leser verstehen oder zumindest eine Ahnung haben, warum das Ergebnis das ist, was es ist.
Anthony Pace
1
Ich habe das Gefühl, dass diese Antwort viel besser ist als die akzeptierte Antwort.
Christian Herenz
3

Das Gleiche gilt für C99 .

Die von allen modernen Prozessoren verwendete IEEE 754-Gleitkommadarstellung weist mehrere spezielle Bitmuster auf, die für positive Unendlichkeit (Vorzeichen = 0, exp = ~ 0, frac = 0), negative Unendlichkeit (Vorzeichen = 1, exp = ~ 0, frac = 0) reserviert sind ) und viele NaN (keine Zahl: exp = ~ 0, frac ≠ 0).

Alles, worüber Sie sich Sorgen machen müssen: Einige Arithmetiken können Gleitkomma-Ausnahmen / Traps verursachen, aber diese sind nicht nur auf diese "interessanten" Konstanten beschränkt.

kurzlebig
quelle
1
Wenn meine Arithmetik also zu groß ist, könnte sie zu einer Inf werden?
Casebash
@Casebash Nein, es wird eine verursachen OverflowError.
wizzwizz4
2

Ich habe eine Einschränkung gefunden, die bisher niemand erwähnt hat. Ich weiß nicht, ob es in praktischen Situationen häufig vorkommt, aber hier ist es der Vollständigkeit halber.

Normalerweise gibt sich die Berechnung einer Zahl Modulo Infinity als Float zurück, aber ein Bruchteil Modulo Infinity gibt zurück nan(keine Zahl). Hier ist ein Beispiel:

>>> from fractions import Fraction
>>> from math import inf
>>> 3 % inf
3.0
>>> 3.5 % inf
3.5
>>> Fraction('1/3') % inf
nan

Ich habe ein Problem mit dem Python-Bug-Tracker gemeldet. Es kann unter https://bugs.python.org/issue32968 eingesehen werden .

Update: Dies wird in Python 3.8 behoben .

Elias Zamaria
quelle
2

Eine sehr schlechte Höhle: Division durch Null

in einem 1/xBruchteil ist x = 1e-323es infaber wann x = 1e-324oder wenig es wirftZeroDivisionError

>>> 1/1e-323
inf

>>> 1/1e-324
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: float division by zero

also sei vorsichtig!

Seyfi
quelle