Negativo NaN non è un NaN?
Domanda
Mentre scrivevo alcuni casi di test, e alcuni dei test per verificare il risultato di un NaN.
Ho provato ad utilizzare std::isnan
ma i failes asserzione:
Assertion `std::isnan(x)' failed.
Dopo aver stampato il valore di x
, è venuto fuori che di negativo NaN (-nan
) che è del tutto accettabile nel mio caso.
Dopo aver cercato di utilizzare il fatto che NaN != NaN
e utilizzando assert(x == x)
, il compilatore mi fa un 'favore' e ottimizza l'asserzione via.
fare la mia propria funzione isNaN
viene ottimizzato via pure.
Come posso controllare sia per l'uguaglianza di NaN e -NaN?
Soluzione
Questo è imbarazzante.
Il motivo per il compilatore (GCC in questo caso) è stata l'ottimizzazione via il confronto e isnan
false
tornato è stato perché qualcuno nella mia squadra aveva acceso -ffast-math
.
Dalla documentazione:
-ffast-math Sets -fno-math-errno, -funsafe-math-optimizations, -fno-trapping-math, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and fcx-limited-range. This option causes the preprocessor macro __FAST_MATH__ to be defined. This option should never be turned on by any -O option since it can result in incorrect output for programs which depend on an exact implementation of IEEE or ISO rules/specifications for math functions.
Si noti la frase finale -. -ffast-math
è pericoloso
Altri suggerimenti
isnan()
dovrebbe avere un comportamento indefinito con -ffast-math
.
Questo è quello che uso nella mia suite di test:
#if defined __FAST_MATH__
# undef isnan
#endif
#if !defined isnan
# define isnan isnan
# include <stdint.h>
static inline int isnan(float f)
{
union { float f; uint32_t x; } u = { f };
return (u.x << 1) > 0xff000000u;
}
#endif
Questo appare come un bug nell'implementazione della vostra libreria di isnan()
a me. Funziona bene qui in gcc 4.2.1 su Snow Leopard. Tuttavia, che dire di provare questo?
std::isnan(std::abs(yourNanVariable));
Ovviamente, non posso provarlo, dal momento che è std::isnan(-NaN)
true
sul mio sistema.
Modifica : Con -ffast-math
, a prescindere dal commutatore -O
, gcc 4.2.1 su Snow Leopard pensa che NAN == NAN
è true
, come è NAN == -NAN
. Questo potrebbe potenzialmente rompere il codice catastroficamente. Vi consiglio lasciando fuori -ffast-math
o almeno test per risultati identici in costruisce utilizzando e non lo si utilizza ...
Non c'è C99 isNaN (), che si dovrebbe essere in grado di utilizzare.
Se nell'implementazione non funziona correttamente (che è che?) È possibile implementare il proprio, per reinterpret_casting a lungo e fare IEEE morse magia.
È possibile controllare i bit di numero. IEEE 754 ha definito maschera per NaN:
- La segnalazione NaN è rappresentata da qualsiasi sequenza di bit tra X'7F80 0001' e X'7FBF FFFF 'o tra X'FF80 0001' e X'FFBF FFFF'.
- Un tranquillo NaN è rappresentata da qualsiasi modello di bit tra X'7FC0 0000' e X'7FFF FFFF 'o tra X'FFC0 0000' e X'FFFF FFFF'.
Questo potrebbe essere non portabile, ma se si è sicuri circa la vostra platfofm può essere accettabile. Più: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm
Questa è basato l'articolo di Wikipedia pubblicato nei commenti. Si noti che è del tutto non testato -. Dovrebbe dare un'idea di qualcosa che si può fare anche se
bool reallyIsNan(float x)
{
//Assumes sizeof(float) == sizeof(int)
int intIzedX = *(reinterpret_cast<int *>(&x));
int clearAllNonNanBits = intIzedX & 0x7F800000;
return clearAllNonNanBits == 0x7F800000;
}
EDIT:. Credo davvero che si dovrebbe considerare un bug con i ragazzi glibc su quello se