Dlaczego double.NaN nie jest sobie równy?


82

Czy ktoś może mi to wyjaśnić? W języku C # double.NaN nie jest równe double.NaN

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

Jaką stałą mogę porównać do podwójnej NaN i uzyskać prawdę?


12
Żeby wyjaśnić, huhs: NaN to nic, nawet samemu sobie. To jest z definicji. en.wikipedia.org/wiki/NaN
Falaina,

2
Myślę, że to niefortunne, to utrata kontekstu. Gdybyśmy mieli dwa podwojenia i obu przypisywano wartość NaN, aby przedstawić rzeczywistą wartość 1/0. Powinny być równe, ale ponieważ kontekst jest stracony, są traktowani jako nierówni
Michael Meadows

13
matematycznie poprawne. Dlaczego ktoś miałby myśleć, że jedna nan będzie równa drugiemu? sqrt (-1)! = 1/0
Gordon Gustafson

2
Jest tak, jak NULLw SQL
shashwat,

2
@MichaelMeadows 1/0 to Inf, a nie NaN.
Jim Balter,

Odpowiedzi:


134

Jeśli jesteś ciekawy, Double.IsNaNwygląda to tak:

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

Funky, co?


11
To jest w porządku. Ale z drugiej strony, taka jest deklaracja NaN:public const double NaN = (double) 1.0 / (double) 0.0;
Fredrik Mörk

5
@Fredik, @Erich: Division by Zero da inf (lub, + inf, -inf na podstawie operandów), 0/0 (między innymi) da w wyniku NaN. Na steve.hollasch.net/cgindex/coding/ieeefloat.html
Torsten Marek.

5
Aby dodać do zamieszania, obiekt.Equals (double.NaN, double.NaN) zwraca true
Román

2
@JimBalter Masz rację, że mój komentarz był błędny: źródło odniesienia faktycznie podaje public const double NaN = (double)0.0 / (double)0.0; link do źródła odniesienia . Dziękuję za zwrócenie uwagi. Z drugiej strony: bycie w błędzie i kłamstwo to dwie zupełnie różne rzeczy
Fredrik Mörk,

1
Nie jestem pewien, czy to było poprawne, kiedy to opublikowałeś, ale IsNaN jest dziś zdefiniowane inaczej .
Joe Amenta



10

Zachowanie jest celowe. Powód, dla którego NaN nie jest liczbą, oznacza coś, co nie jest liczbą, a więc jest to rodzaj przechwytywania wielu rzeczy.

Właściwym sposobem porównania czegoś z byciem NaN jest użycie funkcji IsNaN .




5

Użyj metody „Double.IsNaN (wartość)”, aby sprawdzić ten warunek.


3

Właściwie już znalazłeś sposób, aby sprawdzić, czy liczba zmiennoprzecinkowa IEEE-754 to NaN : jest to jedyna wartość zmiennoprzecinkowa (lub zakres wartości, ponieważ istnieje kilka NaN), która jest obliczana w Falseporównaniu ze sobą, tj .:

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

Pod maską metoda Double.IsNaN może w rzeczywistości zrobić to samo. Powinieneś nadal z niego korzystać, ponieważ zachowanie jest dość zaskakujące dla każdego, kto nie zna standardu FP.


2

Jedyne, co wiemy o NaN, to to, że nie jest to liczba. Nie oznacza to, że ma wartość związaną z jego stanem. Na przykład:

∞ + (-∞) = NaN

0/0 = NaN

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

Oto kilka C # do zademonstrowania

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

Powód Double.NaN != Double.NaNjest prosty:

Czy spodziewasz 0/0się być tym samym, co Math.Sqrt(-3)? I tak samo jak Math.Sqrt(-7)?

Moim zdaniem w C # jest błąd, który Equals()nie jest zastępowany dla NaN.

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

W tym samym czasie

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

Użyj funkcji statycznych dla Doublei Single, np

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

Lub bardziej szczegółowe:

Double.IsPositiveInfinity(value);
Double.IsNegativeInfinity(value);

2

Operator równości uznaje dwie wartości NaN za nierówne. Zasadniczo operatorów Double nie można używać do porównywania Double.NaN z innymi wartościami Double, chociaż metody porównania (takie jak Equals i CompareTo ) mogą. zobacz poniższe przykłady

Odniesienie z 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");
        }
    }
}

tutaj jest .net fiddle dla tego samego.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.