Négatif NaN ne fait pas NaN?
Question
Lors de l'écriture des cas de test, et certains des tests pour vérifier le résultat d'un NaN.
J'ai essayé d'utiliser std::isnan
mais les failes assert:
Assertion `std::isnan(x)' failed.
Après l'impression de la valeur de x
, il est apparu qu'il NaN (de -nan
) de négatif qui est tout à fait acceptable dans mon cas.
Après avoir essayé d'utiliser le fait que NaN != NaN
et en utilisant assert(x == x)
, le compilateur me fait une « faveur » et optimise la assert loin.
Faire ma propre fonction isNaN
est optimisé aussi bien loin.
Comment puis-je vérifier à la fois l'égalité des NaN et -Nan?
La solution
Ceci est gênant.
La raison pour laquelle le compilateur (GCC dans ce cas) a été l'optimisation loin isnan
retourné la comparaison et false
a été parce que quelqu'un dans mon équipe avait tourné sur -ffast-math
.
A partir de la documentation:
-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.
Notez la phrase se terminant -. -ffast-math
est dangereux
Autres conseils
isnan()
devrait avoir un comportement non défini avec -ffast-math
.
est ce que je l'utilise dans ma suite de 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
Cela ressemble à un bug dans la mise en œuvre de votre bibliothèque de isnan()
pour moi. Il fonctionne très bien ici gcc 4.2.1 sur Snow Leopard. Mais qu'en est-essayer cela?
std::isnan(std::abs(yourNanVariable));
De toute évidence, je ne peux pas tester, puisque std::isnan(-NaN)
est true
sur mon système.
EDIT : Avec -ffast-math
, quel que soit le commutateur -O
, gcc 4.2.1 sur Snow Leopard pense que NAN == NAN
est true
, comme NAN == -NAN
. Cela pourrait casser le code catastrophiquement. Je vous conseille de quitter ou de -ffast-math
au moins pour tester des résultats identiques dans les versions à l'aide et ne pas l'utiliser ...
Il y a C99 isnan () que vous devriez être en mesure d'utiliser.
Si dans votre implémentation ne fonctionne pas correctement (ce qui est que?), Vous pouvez mettre en œuvre vos propres, par reinterpret_casting à long et faire de la magie bit IEEE.
Vous pouvez vérifier les bits du nombre. IEEE 754 a défini un masque de NaN:
- A de NaN est représenté par un motif de bits entre X'7F80 0001' et X'7FBF FFFF 'ou entre X'FF80 0001' et X'FFBF FFFF'.
- Un silencieux NaN est représenté par une configuration binaire entre X'7FC0 0000' et X'7FFF FFFF 'ou entre X'FFC0 0000' et X'FFFF FFFF'.
Cela peut être pas portable, mais si vous êtes sûr de votre platfofm il peut être acceptable. En savoir plus: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm
est basé sur l'article de wikipedia posté dans les commentaires. Notez qu'il est tout à fait non testé -. Il devrait vous donner une idée de quelque chose que vous pouvez faire si
bool reallyIsNan(float x)
{
//Assumes sizeof(float) == sizeof(int)
int intIzedX = *(reinterpret_cast<int *>(&x));
int clearAllNonNanBits = intIzedX & 0x7F800000;
return clearAllNonNanBits == 0x7F800000;
}
EDIT:. Je pense vraiment que vous devriez envisager de déposer un bug avec les gars glibc sur celui-là si