Сравнение "float ('nan')" и "math.nan" - PullRequest
1 голос
/ 17 апреля 2019

У меня есть переменная типа float, которая может быть или не быть числом, и я хочу проверить, так ли это. С x = float('nan') я заметил некоторое поведение, которое меня удивило:

    print(x is math.nan)
>>> False

Это означает, что float('nan') и math.nan - это разные объекты, чего я не ожидал, но это нормально. Тем не менее, результат тот же, когда я проверяю равенство с ==:

print(x == math.nan):
>>> False

Я получаю правильный результат для всех видов не чисел, если я использую math.isnan(x). Тем не менее, почему float('nan') == math.nan не оценивается как True?.

Ответы [ 4 ]

2 голосов
/ 17 апреля 2019

«Не число» - это (в некотором смысле) отсутствие значения.

Традиционно, согласно спецификации IEEE с плавающей точкой, не равно .

Это потому, что нет смысла сравнивать.

На самом деле, некоторые люди используют этот факт для обнаружения NaN , поэтому вы можете вместо этого попробовать x != x в качестве условия (хотя у связанных вопросов и ответов, возможно, есть несколько лучших предложений).

Выражение math.nan is math.nan истинно, хотя, потому что is выполняет сравнение идентичности объекта, а не сравнение эквивалентности / равенства значений.

1 голос
/ 17 апреля 2019

Это потому, что NaN это просто значение с плавающей запятой.Использование is не проверяет, имеют ли переменные одинаковое значение, оно проверяет, являются ли они одним и тем же объектом.Если вы создаете два числа с одинаковым значением, это не один и тот же объект, это два объекта с одинаковым значением.Возьмем для примера:

>>> a = float('nan')
>>> b = float('nan')
>>> a is b
False

Таким образом, даже если вы создаете два значения NaN одинаково, они не являются одним и тем же объектом.Это верно даже для более тривиальных операций.Попробуйте это:

>>> a = 1.
>>> b = 1.
>>> a is b
False

Версия Python по умолчанию повторно использует некоторые значения, так что любой экземпляр этого значения является одним и тем же объектом.Возьмем, к примеру, это (обратите внимание на отсутствие десятичного числа, это целые числа, а не числа с плавающей запятой):

>>> a = 1
>>> b = 1
>>> a is b
True

Но это деталь реализации, на которую вы никогда не должны полагаться, она может измениться в любое время и может варьироваться междуреализации Python.Но даже при этом NaN не является одним из значений, для которых интерпретатор Python по умолчанию делает это.

Вы можете проверить, являются ли две переменные одним и тем же объектом, вручную, используя функцию id, которая дает уникальный номер для каждого одновременно существующего объекта (хотя числа можно использовать повторно, если переменная удалена,даже автоматически).

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

Что касается того, почему они не равны, то это лишь часть определения NaN, которое используется на современных компьютерах.По определению NaN никогда не должно быть равным себе.Это часть международного стандарта о том, как работают числа с плавающей запятой, и это поведение встроено в современные процессоры.

1 голос
/ 17 апреля 2019

Это не специальное поведение: is возвращает, действительно ли два объекта ссылаются на одну и ту же вещь (по существу, в памяти), а == возвращает, имеют ли два объекта одинаковое значение.

Чтобы узнать, относятся ли они к одной и той же вещи, мы можем использовать 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

Здесь мы видим, что, присваивая b = a, они теперь ссылаются на один и тот же список: следовательно, is и == равны True. Однако, когда мы определяем c как новую переменную с тем же значением, что и a и b, это ==, но is возвращает False.

То же самое верно для NaN с.

0 голосов
/ 17 апреля 2019

Хотя они не являются одним и тем же объектом (поскольку они принадлежат разным модулям, в которых они были реализованы отдельно), и они не равны (по проекту NaN != NaN), существует функция math.isnan ( и numpy.isnan, если вы хотите векторизованную версию) именно для этой цели:

import math
import numpy

math.isnan(math.nan)
# True
math.isnan(numpy.nan)
# True
math.isnan(float("nan"))
# True

Хотя все они не равны между собой и не идентичны:

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