Почему double.NaN не равно самому себе?

82

Может кто-то объяснить это мне? В C # double.NaN не равно double.NaN.

bool huh = double.NaN == double.NaN; // huh = false
bool huh2 = double.NaN >= 0; // huh2 = false
bool huh3 = double.NaN <= 0; // huh3 = false

Какую константу я могу сравнить с double.NaN и получить истину?

Карло
источник
12
Просто чтобы объяснить вам: NaN ничего не значит, даже сам по себе. Это по определению. en.wikipedia.org/wiki/NaN
Фалаина
2
Я считаю неудачным то, что контекст теряется. Если бы у нас было два двойных, и обоим было присвоено значение NaN, чтобы представить фактическое значение 1/0. Они должны быть равны, но, поскольку контекст утерян, к ним относятся как к неравным
Майкл Медоуз
13
математически правильно. Почему можно подумать, что один нанят будет равен другому? sqrt (-1)! = 1/0
Гордон Густафсон
2
Это как NULLв SQL
шашват
2
@MichaelMeadows 1/0 - это Inf, а не NaN.
Джим Балтер

Ответы:

134

Если вам интересно, вот как Double.IsNaNвыглядит:

public static bool IsNaN(double d)
{
    return (d != d);
}

Обалденный, да?

Эрих Мирабал
источник
11
Это странно. Но опять же, как и заявление NaN:public const double NaN = (double) 1.0 / (double) 0.0;
Fredrik Mörk
5
@Fredik, @Erich: деление на ноль даст inf (или + inf, -inf в зависимости от операндов), 0/0 (среди прочего) даст NaN. На steve.hollasch.net/cgindex/coding/ieeefloat.html
Торстен Марек
5
Чтобы усугубить путаницу, object.Equals (double.NaN, double.NaN) возвращает true
Román
2
@JimBalter Вы правы, что мой комментарий был неправильным: источник ссылки на самом деле public const double NaN = (double)0.0 / (double)0.0; указывает ссылку на источник ссылки . Спасибо что подметил это. С другой стороны, неправда и ложь - две совершенно разные вещи
Фредрик Мёрк
1
Не уверен, что это было правильно на момент публикации, но сегодня IsNaN определяется по-другому .
Джо Амента
10

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

Правильный способ сравнить что-то с NaN - использовать функцию IsNaN .

Майк Динеску
источник
7

Используйте Double.IsNan (), чтобы проверить здесь равенство. Причина в том, что NaN не является числом.

Колин Маккей
источник
6

Для этого есть специальная функция:

double.IsNan(huh);
Арул
источник
5

Используйте метод Double.IsNaN (value), чтобы проверить это условие.

Дэвид
источник
3

Фактически, вы уже нашли способ проверить, является ли число с плавающей запятой IEEE-754 NaN : это единственное значение с плавающей запятой (или диапазон значений, поскольку существует несколько NaN), которое оценивается по Falseсравнению с самим собой, то есть:

bool isNaN(double v) {
    return v != v;
}

Под капотом метод Double.IsNaN может делать то же самое. Вы все равно должны использовать его, потому что поведение довольно удивительно для любого, кто не знает о стандарте FP.

Торстен Марек
источник
2

Единственное, что мы знаем о NaN, - это то, что это «не число». Это не означает, что у него есть значение, связанное с его состоянием. Например:

∞ + (-∞) = NaN

0/0 = NaN

(∞ + (-∞)) <> (0/0)

Вот немного C # для демонстрации

var infinity = 100d / 0;
var negInfinity = -100d / 0;

var notANumber = infinity + negInfinity;
Console.WriteLine("Negative Infinity plus Infinity is NaN: {0}", double.IsNaN(notANumber));

var notANumber2 = 0d / 0d;
Console.WriteLine("Zero divided by Zero is NaN: {0}", double.IsNaN(notANumber2));

Console.WriteLine("These two are not equal: {0}", notANumber == notANumber2);
Майкл Медоуз
источник
2

Причина Double.NaN != Double.NaN проста:

Вы рассчитываете 0/0быть таким же, как Math.Sqrt(-3)? И так же, какMath.Sqrt(-7) ?

На мой взгляд, есть ошибка в C #, Equals()которая не отменяется для NaN.

Assert.IsTrue(Double.NaN != Double.NaN);
Assert.IsTrue(Double.NaN.Equals(Double.NaN));

В то же время

Assert.IsTrue(Double.PositiveInfinity == Double.NegativeInfinity);
Assert.IsTrue(Double.PositiveInfinity.Equals(Double.PositiveInfinity));
// same for Double.NegativeInfinity and Single

Используйте статические функции для Doubleи Single, например

Double.IsNaN(value) && Double.IsInfinity(value);

Или более конкретно:

Double.IsPositiveInfinity(value);
Double.IsNegativeInfinity(value);
Artru
источник
2

Оператор Equality считает, что два значения NaN не равны друг другу. Как правило, операторы Double нельзя использовать для сравнения Double.NaN с другими значениями Double, хотя методы сравнения (например, Equals и CompareTo ) могут. см. ниже примеры

Ссылка из msdn

class Program
{
    static void Main(string[] args)
    {
        Double i = Double.NaN;
        while (!i.Equals(i)) //this would be result in false
        //while(i != i) // this would result in true.
        {
            Console.WriteLine("Hello");
        }
    }
}

вот скрипка .net для того же самого.

Жениш Рабадия
источник