Negative NaN is not a NaN?

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?

29
задан einpoklum - reinstate Monica 20 November 2016 в 00:09
поделиться

4 ответа

Это неловко.

Причина, по которой компилятор (в данном случае 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 небезопасно.

33
ответ дан 28 November 2019 в 01:57
поделиться

Существует C99 isnan(), который вы сможете использовать.

Если в вашей реализации это работает некорректно (какая именно?), вы можете реализовать свою собственную, переинтерпретируя_приведение к long и применяя битовую магию IEEE.

0
ответ дан 28 November 2019 в 01:57
поделиться

Вы можете проверить биты числа. IEEE 754 определил маску для NaN:

  • Сигнальный NaN представлен любой битовой комбинацией между X'7F80 0001' и X'7FBF FFFF' или между X'FF80 0001' и X'FFBF FFFF'.
  • Тихий NaN представлен любой битовой комбинацией между X'7FC0 0000' и X'7FFF FFFF' или между X'FFC0 0000' и X'FFFF FFFF'.

Это может быть не переносимо, но если вы уверены в своей платформе, это может быть приемлемо. Подробнее: http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=/com.ibm.xlf101l.doc/xlfopg/fpieee.htm

0
ответ дан 28 November 2019 в 01:57
поделиться

Это основано на статье в Википедии, размещенной в комментариях. Обратите внимание, что он полностью непроверен, хотя он должен дать вам представление о том, что вы можете сделать.

bool reallyIsNan(float x)
{
    //Assumes sizeof(float) == sizeof(int)
    int intIzedX = *(reinterpret_cast<int *>(&x));
    int clearAllNonNanBits = intIzedX & 0x7F800000;
    return clearAllNonNanBits == 0x7F800000;
}

РЕДАКТИРОВАТЬ: Я действительно думаю, что вам следует подумать о том, чтобы сообщить об ошибке ребятам из GLibc.

-3
ответ дан 28 November 2019 в 01:57
поделиться
Другие вопросы по тегам:

Похожие вопросы: