Notez que la constante 1e309sera interprétée comme +infet -1e309sera interprétée comme -inf.
Chris Taylor
Réponses:
97
Vous pouvez toujours obtenir des valeurs not-a-number (NaN) à partir de l'arithmétique simple impliquant inf:
>>>0* float("inf")
nan
Notez que vous normalement pas obtenir une infvaleur par des calculs arithmétiques usuels:
>>>2.0**24.0>>> _**216.0>>> _**2256.0>>> _**265536.0>>> _**24294967296.0>>> _**21.8446744073709552e+19>>> _**23.4028236692093846e+38>>> _**21.157920892373162e+77>>> _**21.3407807929942597e+154>>> _**2Traceback(most recent call last):File"<stdin>", line 1,in?OverflowError:(34,'Numerical result out of range')
La infvaleur 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 OverflowErrorimmédiatement une exception, plutôt que d'avoir une infvaleur injectée silencieusement dans vos calculs.
Une simple addition de float, une multiplication, etc. produira heureusement inf si: f = 1.3407807929942597e + 154; f * f => inf. Il semble plutôt une exception de ** de lever une OverflowError.
eregon le
@eregon, en fait, **semble un peu bogué. Lorsqu'il déborde de nombres réels, il renvoie une erreur, mais lorsque l'un de ses opérandes est infou -inf, il renvoie soit 0.0ou inf. Ainsi , il fait correctement lorsque l'entrée est inifinty, mais pas lorsque le résultat devrait être infini.
Abel
2
@Abel Ce n'est pas un buggy. Débordant signifie que le nombre est très grand. Trop grand pour le représenter, mais toujours bien plus petit que l'infini. Mettre l'infini dans un tel endroit peut être utile pour le gestionnaire d'exceptions de votre logique d'application particulière, mais serait incorrect pour Python en général.
Lutz Prechelt
6
@Lutz s'il s'agit d'une multiplication, c'est toujours un comportement incohérent. Certainement grand * grand n'est pas non plus l'infini.
Les sections suivantes s'appliquent également à tout langage qui implémente correctement l'arithmétique en virgule flottante IEEE, il n'est pas spécifique à Python.
Comparaison des inégalités
Lorsqu'il s'agit >d' <opérateurs infini et supérieur ou inférieur à , les éléments suivants comptent:
toute comparaison impliquant NaNest fausse ( infn'est ni supérieure, ni inférieure à NaN)
Comparaison pour l'égalité
Lorsqu'on les compare pour l'égalité, +infet +infsont égaux, comme le sont -infet -inf. C'est une question très débattue et peut sembler controversée pour vous, mais c'est dans la norme IEEE et Python se comporte comme ça.
Bien sûr, +infest inégal à -infet tout, y compris NaNlui-même, est inégal à NaN.
Calculs avec l'infini
La plupart des calculs avec l'infini donneront l'infini, sauf si les deux opérandes sont l'infini, lorsque l'opération division ou modulo, ou avec une multiplication avec zéro, il y a quelques règles spéciales à garder à l'esprit:
multiplié par zéro, pour lequel le résultat n'est pas défini, il donne NaN
en divisant un nombre (sauf l'infini lui-même) par l'infini, ce qui donne 0.0ou -0.0².
en divisant (y compris modulo) l'infini positif ou négatif par l'infini positif ou négatif, le résultat n'est pas défini, donc NaN.
lors de la soustraction, les résultats peuvent être surprenants, mais suivent le bon sens mathématique :
lorsque vous faites inf - inf, le résultat est indéfini: NaN;
en faisant inf - -inf, le résultat est inf;
en faisant -inf - inf, le résultat est -inf;
lorsque vous faites -inf - -inf, le résultat est indéfini: NaN.
lors de l'ajout, cela peut également être surprenant:
en faisant inf + inf, le résultat est inf;
lorsque vous faites inf + -inf, le résultat est indéfini: NaN;
lorsque vous faites -inf + inf, le résultat est indéfini: NaN;
en faisant -inf + -inf, le résultat est -inf.
utiliser math.pow, powou **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 s'adapter à un flotteur double précision (il doit renvoyer l'infini), mais lorsque l'entrée est infou -inf, il se comporte correctement et renvoie soit infou 0.0. Lorsque le deuxième argument est NaN, il retourne NaN, sauf si le premier argument est 1.0. Il y a plus de problèmes, pas tous traités dans la documentation .
math.expsouffre des mêmes problèmes que math.pow. Une solution pour résoudre ce problème en cas de débordement consiste à utiliser un code similaire à celui-ci:
try:
res = math.exp(420000)exceptOverflowError:
res = float('inf')
Remarques
Note 1: comme une mise en garde supplémentaire, que tel que défini par la norme IEEE, si le résultat de votre calcul sous-ou déborde, le résultat ne sera pas une erreur de sous-ou de débordement, mais l'infini positif ou négatif: 1e308 * 10.0cède inf.
Remarque 2: étant donné que tout calcul avec des NaNretours NaNet toute comparaison à NaN, y compris NaNlui-même false, vous devez utiliser la math.isnanfonction pour déterminer si un nombre est effectivement NaN.
Remarque 3: bien que Python prenne en charge l'écriture float('-NaN'), le signe est ignoré, car il n'existe pas de connexion en NaNinterne. Si vous divisez -inf / +inf, le résultat est NaNnon -NaN(il n'y a rien de tel).
Remarque 4: veillez à vous fier à l'un des éléments ci-dessus, car Python s'appuie sur la bibliothèque C ou Java pour laquelle il a été compilé et tous les systèmes sous-jacents n'implémentent pas correctement tout ce comportement. Si vous voulez être sûr, testez l'infini avant de faire vos calculs.
¹) signifie récemment depuis la version 3.2 .
²) Les virgules flottantes supportent le zéro positif et négatif, donc: x / float('inf')garde son signe et les -1 / float('inf')rendements -0.0, les 1 / float(-inf)rendements -0.0, les 1 / float('inf')rendements 0.0et les -1/ float(-inf)rendements 0.0. En outre, 0.0 == -0.0quelstrue , vous devez vérifier manuellement le signe si vous ne voulez pas que ce soit vrai.
Un petit pinaillement: tous les calculs avec l'infini ne donnent pas l'infini:-1 * float('infinity') == -inf
Evan Krall
4
C'est pourquoi j'ai dit que c'était un petit pinailleur. Vous m'aviez inquiété pendant une minute que le signe serait totalement ignoré lorsque vous travaillez avec l'infini, et je voulais clarifier pour les autres.
Evan Krall
12
Eh bien, presque: 1 / float ('infinity') == 0.0
Phil
3
@Phil: Bien que je sois à peu près sûr que vous essayiez juste de montrer que tous les calculs avec inf ne résultent pas en inf ou NaN, je voulais juste faire comprendre aux autres personnes qui liront peut-être les commentaires, que 1 / float ('infinity ') == 0.0 est vrai; car, comme vous vous approchez de l'infini, le résultat de la division approche 0. Je sais que ce n'est que du calcul de base, mais je voulais être sûr que ceux qui lisent comprennent, ou du moins ont une idée de pourquoi, le résultat est ce qu'il est.
Anthony Pace
1
J'ai le sentiment que cette réponse est bien meilleure que la réponse acceptée.
La représentation en virgule flottante IEEE 754 utilisée par tous les processeurs modernes a plusieurs modèles de bits spéciaux réservés pour l'infini positif (signe = 0, exp = ~ 0, frac = 0), l'infini négatif (signe = 1, exp = ~ 0, frac = 0 ), et de nombreux NaN (Pas un nombre: exp = ~ 0, frac ≠ 0).
Tout ce dont vous devez vous inquiéter: certaines arithmétiques peuvent provoquer des exceptions / interruptions en virgule flottante, mais celles-ci ne sont pas limitées à ces constantes «intéressantes».
Donc, si mon calcul est trop grand, il pourrait devenir un inf?
Casebash
@Casebash Non, cela provoquera un OverflowError.
wizzwizz4
2
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 ici, c'est par souci d'exhaustivité.
Habituellement, le calcul d'un nombre modulo infinity se retourne lui-même sous forme de flottant, mais une fraction modulo infinity renvoie nan(pas un nombre). Voici un exemple:
>>>from fractions importFraction>>>from math import inf
>>>3% inf
3.0>>>3.5% inf
3.5>>>Fraction('1/3')% inf
nan
1e309
sera interprétée comme+inf
et-1e309
sera interprétée comme-inf
.Réponses:
Vous pouvez toujours obtenir des valeurs not-a-number (NaN) à partir de l'arithmétique simple impliquant
inf
:Notez que vous normalement pas obtenir une
inf
valeur par des calculs arithmétiques usuels:La
inf
valeur est considérée comme une valeur très spéciale avec une sémantique inhabituelle, il est donc préférable de connaîtreOverflowError
immédiatement une exception, plutôt que d'avoir uneinf
valeur injectée silencieusement dans vos calculs.la source
**
semble un peu bogué. Lorsqu'il déborde de nombres réels, il renvoie une erreur, mais lorsque l'un de ses opérandes estinf
ou-inf
, il renvoie soit0.0
ouinf
. Ainsi , il fait correctement lorsque l'entrée est inifinty, mais pas lorsque le résultat devrait être infini.L'implémentation de Python suit assez bien la norme IEEE-754 , que vous pouvez utiliser comme guide, mais elle repose sur le système sous-jacent sur lequel elle a été compilée, de sorte que des différences de plate-forme peuvent survenir. Récemment¹, un correctif a été appliqué qui autorise «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 en virgule flottante IEEE, il n'est pas spécifique à Python.
Comparaison des inégalités
Lorsqu'il s'agit
>
d'<
opérateurs infini et supérieur ou inférieur à , les éléments suivants comptent:+inf
est supérieur à-inf
-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
NaN
est fausse (inf
n'est ni supérieure, ni inférieure àNaN
)Comparaison pour l'égalité
Lorsqu'on les compare pour l'égalité,
+inf
et+inf
sont égaux, comme le sont-inf
et-inf
. C'est une question très débattue et peut sembler controversée pour vous, mais c'est dans la norme IEEE et Python se comporte comme ça.Bien sûr,
+inf
est inégal à-inf
et tout, y comprisNaN
lui-même, est inégal àNaN
.Calculs avec l'infini
La plupart des calculs avec l'infini donneront l'infini, sauf si les deux opérandes sont l'infini, lorsque l'opération division ou modulo, ou avec une multiplication avec zéro, il y a quelques règles spéciales à garder à l'esprit:
NaN
0.0
ou-0.0
².NaN
.inf - inf
, le résultat est indéfini:NaN
;inf - -inf
, le résultat estinf
;-inf - inf
, le résultat est-inf
;-inf - -inf
, le résultat est indéfini:NaN
.inf + inf
, le résultat estinf
;inf + -inf
, le résultat est indéfini:NaN
;-inf + inf
, le résultat est indéfini:NaN
;-inf + -inf
, le résultat est-inf
.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 s'adapter à un flotteur double précision (il doit renvoyer l'infini), mais lorsque l'entrée estinf
ou-inf
, il se comporte correctement et renvoie soitinf
ou0.0
. Lorsque le deuxième argument estNaN
, il retourneNaN
, sauf si le premier argument est1.0
. Il y a plus de problèmes, pas tous traités dans la documentation .math.exp
souffre des mêmes problèmes quemath.pow
. Une solution pour résoudre ce problème en cas de débordement consiste à utiliser un code similaire à celui-ci:Remarques
Note 1: comme une mise en garde supplémentaire, que tel que défini par la norme IEEE, si le résultat de votre calcul sous-ou déborde, le résultat ne sera pas une erreur de sous-ou de débordement, mais l'infini positif ou négatif:
1e308 * 10.0
cèdeinf
.Remarque 2: étant donné que tout calcul avec des
NaN
retoursNaN
et toute comparaison àNaN
, y comprisNaN
lui-mêmefalse
, vous devez utiliser lamath.isnan
fonction pour déterminer si un nombre est effectivementNaN
.Remarque 3: bien que Python prenne en charge l'écriture
float('-NaN')
, le signe est ignoré, car il n'existe pas de connexion enNaN
interne. Si vous divisez-inf / +inf
, le résultat estNaN
non-NaN
(il n'y a rien de tel).Remarque 4: veillez à vous fier à l'un des éléments ci-dessus, car Python s'appuie sur la bibliothèque C ou Java pour laquelle il a été compilé et tous les systèmes sous-jacents n'implémentent pas correctement tout ce comportement. Si vous voulez être sûr, testez l'infini avant de faire vos calculs.
¹) signifie récemment depuis la version 3.2 .
²) Les virgules flottantes supportent le zéro positif et négatif, donc:
x / float('inf')
garde son signe et les-1 / float('inf')
rendements-0.0
, les1 / float(-inf)
rendements-0.0
, les1 / float('inf')
rendements0.0
et les-1/ float(-inf)
rendements0.0
. En outre,0.0 == -0.0
quelstrue
, vous devez vérifier manuellement le signe si vous ne voulez pas que ce soit vrai.la source
-1 * float('infinity') == -inf
Il en va de même pour C99 .
La représentation en virgule flottante IEEE 754 utilisée par tous les processeurs modernes a plusieurs modèles de bits spéciaux réservés pour l'infini positif (signe = 0, exp = ~ 0, frac = 0), l'infini négatif (signe = 1, exp = ~ 0, frac = 0 ), et de nombreux NaN (Pas un nombre: exp = ~ 0, frac ≠ 0).
Tout ce dont vous devez vous inquiéter: certaines arithmétiques peuvent provoquer des exceptions / interruptions en virgule flottante, mais celles-ci ne sont pas limitées à ces constantes «intéressantes».
la source
OverflowError
.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 ici, c'est par souci d'exhaustivité.
Habituellement, le calcul d'un nombre modulo infinity se retourne lui-même sous forme de flottant, mais une fraction modulo infinity renvoie
nan
(pas un nombre). Voici un exemple:J'ai déposé un problème sur le traqueur de bogues Python. Il peut être vu à https://bugs.python.org/issue32968 .
Mise à jour: cela sera corrigé dans Python 3.8 .
la source
en une
1/x
fraction, jusqu'àx = 1e-323
c'estinf
mais quandx = 1e-324
ou peu il jetteZeroDivisionError
alors soyez prudent!
la source