Porównywanie NaN-ów

0
#include <iostream>
#include <limits>


#define WRITE_F2U(x) std::cout<<(#x)<<" == "<<convertFloatToBinary(x)<<"\n" ;
#define OUT_S(x) std::cout<<(#x)<<" == "<<(x)<<"\n" ;

unsigned convertFloatToBinary(float f)
{
	return *reinterpret_cast<unsigned*>(&f) ;
}

int main(int argc, char **argv)
{
	float f1 = std::numeric_limits<float>::quiet_NaN() ;
	
	bool b1 = f1==std::numeric_limits<float>::quiet_NaN() ; //zawsze false
	bool b2 = !(f1==f1) ; //zawsze true
	
	OUT_S(b1) ;
	OUT_S(b2) ;
	OUT_S(f1) ;
	
	WRITE_F2U(f1);
	WRITE_F2U(f1);
	WRITE_F2U(std::numeric_limits<float>::quiet_NaN());
	
	return 0;
}

wynik:

b1 == 0
b2 == 1
f1 == nan
f1 == 2143289344
f1 == 2143289344
std::numeric_limits<float>::quiet_NaN() == 2143289344

Znam wystarczająco standard IEEE754, wiem, że sprawdza się, czy liczba jest nanem właśnie w drugi sposób. Ale właściwie dlaczego tak? Dlaczego ta liczba "nie jest równa sobie"?

0
WIKI napisał(a)

NaN – ang.: Not a Number, ustawione wszystkie bity wykładnika, mantysa różna od 0, może się pojawić np. jako wynik pierwiastkowania liczby ujemnej

Czy sqrt(-2) jest równe sqrt(-3)?

0

"One other complication is that comparisons involving NANs are always supposed to return false, but AlmostEqual2sComplement will say that two NANs are equal to each other if they have the same integer representation. "

Wprost z opisu standardu - porównania z NaNem zwracają false, oprócz AlmostEqual2sComplement (opis chociażby http://www.working-software.com/node/35 ).

BTW

MarekR22 napisał(a)
WIKI napisał(a)

NaN – ang.: Not a Number, ustawione wszystkie bity wykładnika, mantysa różna od 0, może się pojawić np. jako wynik pierwiastkowania liczby ujemnej

Czy sqrt(-2) jest równe sqrt(-3)?

Z tej samej wiki:
"For example, a bit-wise example of a IEEE floating-point standard single precision (32-bit) NaN would be: s111 1111 1axx xxxx xxxx xxxx xxxx xxxx"

Czyli sqrt(-2) != sqrt(-3) , również na poziomie binarnym.
Prawdopodobnie sqrt(-2) == sqrt(-2) równa się na poziomie binarnym, jednak jak mówi standard - gdy któryś z operandów porównania jest NaN to false.

BTW Twój kod na gcc:
http://ideone.com/Zq6ph

Wyjście inne - widać tutaj też zależność od kompilatora co robi dokładnie z NaN'mi.

0
lemm napisał(a)

BTW Twój kod na gcc:
http://ideone.com/Zq6ph

Wyjście inne - widać tutaj też zależność od kompilatora co robi dokładnie z NaN'mi.

WTF jakim cudem WRITE_F2U(f1); za drugim razem zwraca coś innego?

Coś dziwnie działa to ideone, taki kod http://ideone.com/ID6wB u mnie pod g++ daje wynik:

sizeof(float) == 4
sizeof(unsigned) == 4
b1 == 0
b2 == 1
f1 == nan
std::sqrt(-2) == ffc00000
std::sqrt(-4) == ffc00000
std::sqrt(-8) == ffc00000
std::sqrt(-9) == ffc00000
std::sqrt(-6) == ffc00000
std::sqrt(-3) == ffc00000
!(f1==f1) == 3f800000
f1 == 7fc00000
f1 == 7fc00000
f1 == 7fc00000
f1 == 7fc00000
std::numeric_limits<float>::quiet_NaN() == 7fc00000

0

Może inna wersja, ale nie o to chodzi - o ile na poziomie binarnym będą równe, to przy porównaniu na koprocesorze - jeżeli jeden z nich jest NaN - już nie. To mówi standard i nie ma co więcej rozmyślać chyba na ten temat 'dlaczego' ;>

BTW znowu tutaj ze strony GCC na ideone jest zmiana:
(...)
!(f1==f1) == ffc00000
f1 == 3f800000
f1 == 7fc00000
(...)
A te dwa f1ki to:
0111111100000000000000000000000
1111111110000000000000000000000
Widać, że zmieniły się tylko flagi s i a (*If a = 1, it is a quiet NaN; if a is zero and the payload is nonzero, then it is a signaling NaN.)
Czyli ustawił "pewny" quiet NaN.

1 użytkowników online, w tym zalogowanych: 0, gości: 1