J'ai une variable flottante qui peut ou non être un nombre, et je veux vérifier si c'est le cas. Avec x = float ('nan')
, j'ai observé un comportement qui m'a surpris:
>>> False
print(x == math.nan):
Cela signifie que float ('nan')
et math.nan
sont des objets différents, ce à quoi je ne m'attendais pas, mais ça va. Cependant, le résultat est le même, quand je vérifie l'égalité avec ==
:
>>> False
print(x is math.nan)
j'obtiens le résultat correct pour toutes sortes de not-a-number, si j'utilise math.isnan (x)
. Pourtant, pourquoi float ('nan') == math.nan
n'évalue pas à Vrai
?.
4 Réponses :
"Pas un nombre" est (dans un certain sens) l'absence de valeur.
Traditionnellement, et selon la spécification à virgule flottante IEEE, il ne s'égale pas .
C'est parce qu'il n'y a pas de valeur significative à comparer.
En fait, certaines personnes utilisent ce fait pour détecter NaN , vous pouvez donc essayer x! = x
comme condition à la place (bien que les questions-réponses liées aient sans doute de meilleures suggestions).
L'expression math.nan est math.nan
est cependant vraie, car is
effectue une comparaison d'identité d'objet plutôt qu'une comparaison d'équivalence / égalité de valeur. p >
Curieux de savoir comment vous expliquez: >>> math.nan est math.nan True
.
Merci d'avoir répondu! (@JoeIddon: Cela a absolument du sens tant que math.nan == math.nan
est évalué comme False
. Identique mais pas égal - cas curieux!)
@JoeIddon Identity, comme vous l'avez expliqué dans votre propre réponse. Pas la même chose que l'égalité / équivalence.
Ce n'est pas un comportement spécial: is
renvoie si deux objets font réellement référence à la même chose (essentiellement en mémoire) et ==
retourne si deux objets ont le même value.
Pour voir s'ils se réfèrent à la même chose, nous pouvons utiliser id()
.
>>> a = [1,2,3] >>> b = a >>> id(a) 140302781856200 >>> id(b) 140302781856200 >>> a == b True >>> a is b True >>> c = [1,2,3] >>> id(c) 140302781864904 >>> a == c True >>> a is c False
Ici, nous voyons cela en attribuant b = a
, ils font désormais référence à la même liste: donc est
et ==
sont True
. Cependant, lorsque nous définissons c
comme une nouvelle variable avec la même valeur que a
et b
, c'est == code >, mais
is
renvoie False
.
Il en va de même pour les NaN
s.
p >
Vous avez raison dans le cas de is
, mais sinon c'est est un comportement spécial.
C'est parce que NaN
n'est qu'une valeur flottante. L'utilisation de is
ne vérifie pas si les variables ont la même valeur, mais vérifie s'il s'agit du même objet. Si vous créez deux flottants avec la même valeur, ce ne sont pas le même objet, ce sont deux objets avec la même valeur. Prenez ceci par exemple:
>>> a=1. >>> b=1. >>> c=float('nan') >>> d=float('nan') >>> e=1 >>> f=1 >>> id(a) 139622774035752 >>> id(b) 139622774035872 >>> id(c) 139622774035824 >>> id(d) 139622774035800 >>> id(e) 139622781650528 >>> id(f) 139622781650528
Ainsi, même si vous créez deux valeurs NaN
de la même manière, ce ne sont pas le même objet. Cela est vrai même pour les flotteurs plus triviaux. Essayez ceci:
>>> a = 1 >>> b = 1 >>> a is b True
La version par défaut de Python réutilise certaines valeurs, de sorte que toute instance de cette valeur soit le même objet. Alors prenez ceci par exemple (notez le manque de décimal, ce sont des entiers et non des flottants):
>>> a = 1. >>> b = 1. >>> a is b False
Mais c'est un détail d'implémentation sur lequel vous ne devriez jamais vous fier, il peut changer à à tout moment et peut varier entre les implémentations de python. Mais même avec cela, NaN
n'est pas l'une des valeurs pour lesquelles l'interpréteur Python par défaut fait cela.
Vous pouvez vérifier si deux variables sont le même objet manuellement en utilisant la fonction id
, qui donne un numéro unique pour chaque objet existant simultanément (bien que les nombres puissent être réutilisés si une variable est supprimée, même automatiquement).
>>> a = float('nan') >>> b = float('nan') >>> a is b False
Quant à savoir pourquoi elles ne sont pas égales, c'est juste une partie de la définition de NaN telle qu'elle est utilisée sur les ordinateurs modernes . Par définition, NaN
ne doit jamais être égal à lui-même. Il fait partie d'une norme internationale sur le fonctionnement des nombres à virgule flottante, et ce comportement est intégré aux processeurs modernes.
Bien qu'ils ne soient pas le même objet (car ils proviennent de modules différents où ils ont été implémentés séparément) et qu'ils ne sont pas égaux (par conception NaN! = NaN
), il y a la fonction math.isnan
(et numpy.isnan
si vous veulent une version vectorisée) exactement à cet effet:
math.nan == numpy.nan or math.nan is numpy.nan # False math.nan == float("nan") or math.nan is float("nan") # False numpy.nan == float("nan") or numpy.nan is float("nan") # False
Bien qu'ils soient tous inégaux entre eux et non identiques:
import math import numpy math.isnan(math.nan) # True math.isnan(numpy.nan) # True math.isnan(float("nan")) # True
Selon la spécification IEEE
math.nan! = Math.nan
. C'est comme ça. Et c'est pourquoi les modules mathématiques ontinsnan