web-dev-qa-db-fra.com

Python Infinity - Des mises en garde?

Donc, Python a l'infini positif et négatif:

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

Cela semble être le type de fonctionnalité qui doit être mis en garde. Y a-t-il quelque chose que je devrais être au courant?

172
Casebash

Vous pouvez toujours obtenir des valeurs non numériques (NaN) à partir d'une simple arithmétique impliquant inf:

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

Notez que vous obtiendrez normalement pas une valeur inf par des calculs arithmétiques usuels:

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

La valeur inf est considérée comme une valeur très spéciale avec une sémantique inhabituelle. Il est donc préférable de connaître immédiatement une OverflowError via une exception, plutôt que d'avoir une valeur inf injectée silencieusement dans vos calculs. .

96
Greg Hewgill

L'implémentation de Python suit assez bien le standard IEEE-754 , que vous pouvez utiliser comme guide, mais elle repose sur le système sous-jacent sur lequel elle a été compilée. , donc différences de plate-forme peuvent se produire. Récemment¹, un correctif a été appliqué qui permet "l'infini" ainsi que "inf" , mais c'est d'une importance mineure ici.

Les sections suivantes s'appliquent également à tout langage qui implémente correctement l'arithmétique à virgule flottante IEEE; il n'est pas spécifique à Python.

Comparaison pour l'inégalité

Lorsqu’il s’agit d’opérateurs infini et supérieurs à > ou inférieurs à <, les éléments suivants comptent:

  • tout nombre comprenant +inf est supérieur à -inf
  • tout nombre incluant -inf est inférieur à +inf
  • +inf n'est ni supérieur ni inférieur à +inf
  • -inf n'est ni supérieur ni inférieur à -inf
  • toute comparaison impliquant NaN est fausse (inf n'est ni supérieur ni inférieur à NaN)

Comparaison pour l'égalité

Lorsque l'égalité est comparée, +inf et +inf sont égaux, de même que -inf et -inf. C’est une question très discutée et qui peut paraître controversée, mais elle est conforme à la norme IEEE et Python se comporte exactement comme cela.

Bien entendu, +inf est différent de -inf et tout, y compris NaN lui-même, est différent de NaN.

Calculs à l'infini

La plupart des calculs avec l'infini donneront l'infini, à moins que les deux opérandes ne soient l'infini, que l'opération division ou modulo, ou la multiplication par zéro, prévoient certaines règles spéciales:

  • multiplié par zéro pour lequel le résultat est indéfini, il donne NaN
  • en divisant un nombre quelconque (sauf l'infini lui-même) par l'infini, ce qui donne 0.0 ou -0.0 ².
  • lorsque vous divisez (y compris modulo) l'infini positif ou négatif par l'infini positif ou négatif, le résultat est indéfini, donc NaN.
  • lors de la soustraction, les résultats peuvent être surprenants, mais suivez le sens mathématique commun :
    • lorsque inf - inf est exécuté, le résultat est indéfini: NaN;
    • lorsque inf - -inf est exécuté, le résultat est inf;
    • lorsque -inf - inf est exécuté, le résultat est -inf;
    • lorsque -inf - -inf est exécuté, le résultat est indéfini: NaN.
  • lors de l'ajout, cela peut également être surprenant:
    • lorsque inf + inf est exécuté, le résultat est inf;
    • lorsque inf + -inf est exécuté, le résultat est indéfini: NaN;
    • lorsque -inf + inf est exécuté, le résultat est indéfini: NaN;
    • lorsque -inf + -inf est exécuté, le résultat est -inf.
  • utiliser math.pow, pow ou ** est délicat, car il ne se comporte pas comme il se doit. Il lève une exception de dépassement de capacité lorsque le résultat avec deux nombres réels est trop élevé pour un flottant à double précision (il devrait renvoyer l'infini), mais lorsque l'entrée est inf ou -inf, il se comporte correctement et renvoie soit inf, soit 0.0. Lorsque le deuxième argument est NaN, il renvoie NaN, sauf si le premier argument est 1.0. Il y a plus de problèmes, pas tous couverts dans la documentation .
  • math.exp souffre des mêmes problèmes que math.pow. Une solution pour résoudre ce problème de débordement consiste à utiliser un code similaire à celui-ci:

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

Remarques

Remarque 1: comme mise en garde supplémentaire, telle que définie par le standard IEEE, si le résultat de votre calcul est trop faible ou trop élevé, le résultat ne sera pas inférieur à - ou erreur de débordement, mais infini positif ou négatif: 1e308 * 10.0 donne inf.

Remarque 2: , car tout calcul avec NaN renvoie NaN et toute comparaison avec NaN, y compris NaN lui-même est false, vous devez utiliser le math.isnan fonction pour déterminer si un nombre est bien NaN.

Remarque 3: bien que Python prenne en charge l'écriture float('-NaN'), le signe est ignoré, car il n'existe aucun signe NaN en interne. . Si vous divisez -inf / +inf, le résultat est NaN et non pas -NaN (cela n'existe pas).

Remarque 4: veillez à vous fier à l'un des éléments ci-dessus, car Python s'appuie sur le C ou Java. _ bibliothèque pour laquelle elle a été compilée et tous les systèmes sous-jacents n’implémentent pas correctement tout ce comportement. Si vous voulez en être sûr, testez l'infini avant de faire vos calculs.

¹) Récemment signifie depuis version 3.2 .
²) Les points flottants supportent le zéro positif et négatif, ainsi: x / float('inf') conserve son signe et -1 / float('inf') donne -0.0, 1 / float(-inf) donne -0.0, 1 / float('inf') donne 0.0 et -1/ float(-inf) donne 0.0. De plus, 0.0 == -0.0 EST true , vous devez vérifier le signe manuellement si vous ne voulez pas qu'il soit vrai.

99
Abel

Ainsi fait C99 .

La représentation en virgule flottante IEEE 754 utilisée par tous les processeurs modernes comporte plusieurs modèles de bits spéciaux réservés aux infinis positifs (signe = 0, exp = ~ 0, frac = 0), infinis négatifs (signe = 1, exp = ~ 0, frac = 0). ), et beaucoup de NaN (pas un nombre: exp = ~ 0, frac 0).

Tout ce dont vous avez besoin de vous inquiéter: certaines arithmétiques peuvent causer des exceptions/pièges à virgule flottante, mais ceux-ci ne se limitent pas à ces constantes "intéressantes".

3
ephemient

J'ai trouvé une mise en garde que personne n'a encore mentionnée. Je ne sais pas si cela se produira souvent dans des situations pratiques, mais le voici par souci d'exhaustivité.

Généralement, le calcul d’un nombre modulo infini se retourne sous forme de float, mais une fraction modulo infinity renvoie nan (pas un nombre). Voici un exemple:

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

J'ai signalé un problème sur le traqueur de bogues Python. On peut le voir à https://bugs.python.org/issue32968 .

Mise à jour: ce sera corrigé dans Python 3.8 .

2
Elias Zamaria