Отрицательный NaN не является NaN?
Вопрос
При написании некоторых тестовых примеров некоторые тесты проверяют результат NaN.
Я попробовал использовать std::isnan
но утверждение не выполняется:
Assertion `std::isnan(x)' failed.
После печати значения x
, оказалось, что это отрицательный NaN (-nan
), что в моем случае вполне приемлемо.
После попытки использовать тот факт, что NaN != NaN
и используя assert(x == x)
, компилятор оказывает мне «одолжение» и оптимизирует утверждение.
Делаю свой собственный isNaN
функция также оптимизируется.
Как я могу проверить равенство NaN и -НаН?
Решение
Это раздражительно.
Причина компилятора (GCC в этом случае) оптимизировала сравнение и isnan
вернулся false
было потому, что кто-то в моей команде включил -ffast-math
.
Из документов:
-FAST-математические наборы -FNO-MATH-ERRNO, -FUNSAFE-MATH-ОПТИМАТИЗАЦИИ, -ФНО-ТОЛОВЫЕ, ТОЛЬКО-ТЛИН-ТОЛЬКО-ТОЛЬКО-ТОЛЬКО-ТОЛЬКО-ТОЛЬКОМУКИ, -Наспинги-Округления, -FNO-NANS и FCX Limited -спектр. Эта опция приводит к определению препроцессора __Fast_Math__. Эта опция никогда не должна быть включена в любой опция -O, поскольку она может привести к неправильному выходу для программ, которые зависят от точной реализации правил / спецификаций IEEE или ISO для математических функций.
Обратите внимание на окончательное предложение - -ffast-math
небезопасно.
Другие советы
isnan()
ожидается, что будет неопределенное поведение с -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
Это похоже на ошибку в реализации вашей библиотеки isnan()
мне. Здесь работает нормально, на GCC 4.2.1 на снежном леопарде. Тем не менее, как насчет попробовать это?
std::isnan(std::abs(yourNanVariable));
Очевидно, я не могу это проверить, так как std::isnan(-NaN)
является true
в моей системе.
РЕДАКТИРОВАТЬ: С участием -ffast-math
, независимо от -O
Переключатель, GCC 4.2.1 на снежном леопарде думает, что NAN == NAN
является true
, как есть NAN == -NAN
. Отказ Это может потенциально сломать код катастрофически. Я бы посоветовал уйти -ffast-math
Или, по крайней мере, тестирование на одинаковые результаты в сборках, использующих и не используя его ...
Есть C99 Isnan (), который вы должны быть в состоянии использовать.
Если в вашей реализации он не работает правильно (какой из них что?) Вы можете реализовать свои собственные, ReinterPret_casting в долгое время и делать бит-магию IEEE.
Вы можете проверить биты числа.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
Это основано на статье Википедии, размещенной в комментариях. Обратите внимание, что это совсем непроверено - это должно дать вам представление о том, что вы можете сделать, хотя.
bool reallyIsNan(float x)
{
//Assumes sizeof(float) == sizeof(int)
int intIzedX = *(reinterpret_cast<int *>(&x));
int clearAllNonNanBits = intIzedX & 0x7F800000;
return clearAllNonNanBits == 0x7F800000;
}
Редактировать: Я действительно думаю, что вы должны подумать о том, чтобы подать ошибку с помощью Glibc ребята на этом одном.