While writing some test cases, and some of the tests check for the result of a NaN.
I tried using std::isnan
but the assert failes:
Assertion `std::isnan(x)' failed.
After printing the value of x
, it turned out it's negative NaN (-nan
) which is totally acceptable in my case.
After trying to use the fact that NaN != NaN
and using assert(x == x)
, the compiler does me a 'favor' and optimises the assert away.
Making my own isNaN
function is being optimised away as well.
How can I check for both equality of NaN and -NaN?
Это неловко.
Причина, по которой компилятор (в данном случае GCC) оптимизировал сравнение и isnan
вернул false
, заключалась в том, что кто-то из моей команды включил -ffast-math
.
Из документов:
-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.
Обратите внимание, что последнее предложение — -ffast-math
небезопасно.
Существует C99 isnan(), который вы сможете использовать.
Если в вашей реализации это работает некорректно (какая именно?), вы можете реализовать свою собственную, переинтерпретируя_приведение к long и применяя битовую магию IEEE.
Вы можете проверить биты числа. IEEE 754 определил маску для NaN:
Это может быть не переносимо, но если вы уверены в своей платформе, это может быть приемлемо. Подробнее: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm
Это основано на статье в Википедии, размещенной в комментариях. Обратите внимание, что он полностью непроверен, хотя он должен дать вам представление о том, что вы можете сделать.
bool reallyIsNan(float x)
{
//Assumes sizeof(float) == sizeof(int)
int intIzedX = *(reinterpret_cast<int *>(&x));
int clearAllNonNanBits = intIzedX & 0x7F800000;
return clearAllNonNanBits == 0x7F800000;
}
РЕДАКТИРОВАТЬ: Я действительно думаю, что вам следует подумать о том, чтобы сообщить об ошибке ребятам из GLibc.