سؤال

أثناء كتابة بعض حالات الاختبار ، وبعض الاختبارات تحقق من نتيجة NAN.

حاولت استخدام std::isnan لكن التأكيد فشل:

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

بعد طباعة قيمة x, ، اتضح أنه نان سلبي (-nan) وهو أمر مقبول تمامًا في حالتي.

بعد محاولة استخدام حقيقة ذلك NaN != NaN واستخدام assert(x == x), ، المترجم يقوم بي "صالح" ويحسن التأكيد بعيدًا.

صنع بلدي isNaN يتم تحسين الوظيفة أيضًا.

كيف يمكنني التحقق من كل من مساواة 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 غير آمن.

نصائح أخرى

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 على Snow Leopard. ومع ذلك ، ماذا عن تجربة هذا؟

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

من الواضح أنه لا يمكنني اختباره منذ ذلك الحين std::isnan(-NaN) هو true على نظامي.

تعديل: مع -ffast-math, ، بغض النظر عن -O Switch ، GCC 4.2.1 على Snow Leopard يعتقد ذلك NAN == NAN هو true, ، كما هي NAN == -NAN. هذا يمكن أن يكسر رمز كارثي. أنصح الخروج -ffast-math أو على الأقل اختبار لنتائج متطابقة في البناء باستخدام وعدم استخدامه ...

هناك C99 isnan () والتي يجب أن تكون قادرًا على استخدامها.

إذا كان ذلك في تطبيقك لا يعمل بشكل صحيح (أيهما هذا؟) يمكنك تنفيذ خاص بك ، من خلال إعادة PRET_CASTING إلى Long والقيام بسحر IEEE Bit.

يمكنك التحقق من أجزاء الرقم. حدد 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

يستند هذا إلى مقال ويكيبيديا المنشور في التعليقات. لاحظ أنه لم يتم اختباره تمامًا - يجب أن يعطيك فكرة عن شيء يمكنك القيام به.

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

تحرير: أعتقد حقًا أنك يجب أن تفكر في تقديم خطأ مع شباب GLIBC على ذلك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top