2
votes

Comparaison de "float ('nan')" et "math.nan"

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?.


1 commentaires

Selon la spécification IEEE math.nan! = Math.nan . C'est comme ça. Et c'est pourquoi les modules mathématiques ont insnan


4 Réponses :


3
votes

"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.


3 commentaires

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.



1
votes

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 >


1 commentaires

Vous avez raison dans le cas de is , mais sinon c'est est un comportement spécial.



1
votes

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.


0 commentaires

0
votes

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


0 commentaires