Wiem, że normalnie nie można polegać na równości między wartościami typu podwójnego lub dziesiętnego, ale zastanawiam się, czy 0 to przypadek specjalny.
Chociaż rozumiem niedokładności między 0,00000000000001 a 0,00000000000002, samo 0 wydaje się dość trudne do zepsucia, ponieważ to po prostu nic. Jeśli nic nie jesteś dokładny, to już nie jest nic.
Ale nie wiem zbyt wiele na ten temat, więc nie mogę o tym mówić.
double x = 0.0;
return (x == 0.0) ? true : false;
Czy to zawsze będzie prawdą?
Odpowiedzi:
Można bezpiecznie oczekiwać, że porównanie zwróci
true
wtedy i tylko wtedy, gdy podwójna zmienna ma wartość dokładnie0.0
(co oczywiście ma miejsce w oryginalnym fragmencie kodu). Jest to zgodne z semantyką==
operatora.a == b
oznacza „a
równa sięb
”.Nie jest bezpieczne (ponieważ nie jest poprawne ) oczekiwanie, że wynik niektórych obliczeń będzie wynosił zero w arytmetyce podwójnej (lub bardziej ogólnie, zmiennoprzecinkowej), ilekroć wynik tego samego obliczenia w czystej matematyce wynosi zero. Dzieje się tak, ponieważ gdy obliczenia zaczynają się pojawiać, pojawia się błąd precyzji zmiennoprzecinkowej - pojęcie, które nie istnieje w arytmetyce liczb rzeczywistych w matematyce.
źródło
Jeśli potrzebujesz wykonać wiele porównań „równości”, dobrym pomysłem może być napisanie małej funkcji pomocniczej lub metody rozszerzającej w .NET 3.5 do porównania:
Można to wykorzystać w następujący sposób:
źródło
Dla twojej prostej próbki ten test jest w porządku. Ale co z tym:
Pamiętaj, że .1 to powtarzający się dziesiętny w systemie dwójkowym i nie może być dokładnie reprezentowany. Następnie porównaj to z tym kodem:
Zostawię ci przeprowadzenie testu, aby zobaczyć rzeczywiste wyniki: bardziej prawdopodobne jest, że zapamiętasz to w ten sposób.
źródło
Z wpisu MSDN dla Double.Equals :
Zobacz także Double.Epsilon .
źródło
x.Equals(y)
, wtedy(1/x).Equals(1/y)
, ale tak niex
jest, jeśli jest0
iy
jest1/Double.NegativeInfinity
. Wartości te są deklarowane jako równe, chociaż ich odwrotności nie.x = 0
iy = 0
, i nadal to znajdziesz1/x != 1/y
.x
iy
jako typdouble
? Jak porównujecie wyniki, aby zgłaszać nierówności? Zauważ, że 1 / 0,0 nie jest NaN.1.0/0.0
nie jest to NaN tak, jak powinno, ponieważ granica nie jest wyjątkowa. Po drugie, że nieskończoności porównują się równo ze sobą, bez zwracania uwagi na stopnie nieskończoności)Problem pojawia się, gdy porównujesz różne typy implementacji wartości zmiennoprzecinkowych, np. Porównując zmiennoprzecinkowe z double. Ale z tym samym typem nie powinno to stanowić problemu.
Problem w tym, że programista czasami zapomina, że niejawne rzutowanie typu (double na float) ma miejsce dla porównania i skutkuje to błędem.
źródło
Jeśli liczba została bezpośrednio przypisana do liczby zmiennoprzecinkowej lub podwójnej, można bezpiecznie przetestować względem zera lub dowolnej liczby całkowitej, którą można przedstawić za pomocą 53 bitów dla liczby podwójnej lub 24 bitów dla liczby zmiennoprzecinkowej.
Inaczej mówiąc, zawsze możesz przypisać podwójną wartość i wartość całkowitą, a następnie porównać podwójną wartość z powrotem do tej samej liczby całkowitej i mieć pewność, że będzie równa.
Możesz również zacząć od przypisania liczby całkowitej i wykonywać proste porównania, kontynuując pracę, trzymając się dodawania, odejmowania lub mnożenia przez liczby całkowite (zakładając, że wynik jest mniejszy niż 24 bity dla liczby zmiennoprzecinkowej i 53 bity dla podwójnej). Możesz więc traktować liczby zmiennoprzecinkowe i podwojenia jako liczby całkowite w pewnych kontrolowanych warunkach.
źródło
Nie, to nie jest w porządku. Tak zwane zdenormalizowane wartości (subnormal), w porównaniu do 0,0, byłyby porównywane jako fałszywe (niezerowe), ale użyte w równaniu byłyby znormalizowane (stały się 0,0). Dlatego używanie tego jako mechanizmu unikania dzielenia przez zero nie jest bezpieczne. Zamiast tego dodaj 1.0 i porównaj z 1.0. Zapewni to traktowanie wszystkich wartości podrzędnych jako zero.
źródło
Spróbuj tego, a przekonasz się, że == nie jest wiarygodne dla double / float.
double d = 0.1 + 0.2; bool b = d == 0.3;
Oto odpowiedź od firmy Quora.
źródło
Właściwie myślę, że lepiej jest użyć następujących kodów, aby porównać podwójną wartość z 0,0:
To samo dotyczy float:
źródło