Подтвердить что ты не робот

Отрицательный NaN не является NaN?

При написании некоторых тестовых примеров, а некоторые тесты проверяют результат NaN.

Я попытался использовать std::isnan, но утверждение не удалось:

Assertion `std::isnan(x)' failed.

После печати значения x оказалось, что это отрицательное NaN (-nan), что вполне приемлемо в моем случае.

Попытавшись использовать тот факт, что NaN != NaN и используя assert(x == x), компилятор делает мне "пользу" и оптимизирует утверждение.

Кроме того, оптимизируется моя функция isNaN.

Как я могу проверить как равенство NaN, так и -NaN?

4b9b3361

Ответ 1

Это неловко.

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

Ответ 2

Ожидается, что

isnan() будет иметь поведение undefined с -ffast-math.

Это то, что я использую в своем тестовом наборе:

#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

Ответ 3

Это выглядит как ошибка в реализации библиотеки isnan() для меня. Он отлично работает здесь на gcc 4.2.1 на Snow Leopard. Однако, как насчет этого?

std::isnan(std::abs(yourNanVariable));

Очевидно, я не могу его протестировать, так как std::isnan(-NaN) есть true в моей системе.

РЕДАКТИРОВАТЬ. С -ffast-math, независимо от переключателя -O, gcc 4.2.1 на Snow Leopard считает, что NAN == NAN есть true, как и NAN == -NAN. Это может привести к катастрофическому повреждению кода. Я бы посоветовал отказаться от -ffast-math или хотя бы тестировать одинаковые результаты в сборках, используя и не используя его...

Ответ 4

Здесь C99 isnan(), который вы должны использовать.

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

Ответ 5

Вы можете проверить бит числа. 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'.

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

Ответ 6

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

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

EDIT: Я действительно думаю, что вам стоит подумать о том, чтобы найти ошибку с парнями GLibc на этом.