C ++ 14 के अनुसार परीक्षण के कई तरीके हैं यदि फ्लोटिंग पॉइंट नंबर value
NaN है।
इन तरीकों में से, केवल संख्या के प्रतिनिधित्व के बिट्स की जांच करना , मज़बूती से काम करता है, जैसा कि मेरे मूल उत्तर में उल्लेखित है। विशेष रूप से, std::isnan
और अक्सर प्रस्तावित चेक v != v
, मज़बूती से काम नहीं करते हैं और इसका उपयोग नहीं किया जाना चाहिए, ऐसा न हो कि आपके कोड सही ढंग से काम करना बंद कर दें जब कोई तय करता है कि फ्लोटिंग पॉइंट ऑप्टिमाइज़ेशन की आवश्यकता है, और कंपाइलर को ऐसा करने के लिए कहता है। यह स्थिति बदल सकती है, संकलक अधिक अनुरूप हो सकते हैं, लेकिन इस मुद्दे के लिए जो मूल उत्तर के बाद से 6 वर्षों में नहीं हुआ है।
लगभग 6 वर्षों तक मेरा मूल उत्तर इस प्रश्न के लिए चयनित समाधान था, जो ठीक था। लेकिन हाल ही में अविश्वसनीय v != v
परीक्षण की सिफारिश करने वाले एक अत्यधिक उत्क्रमित उत्तर का चयन किया गया है। इसलिए यह अतिरिक्त अप-टू-डेट उत्तर (हमारे पास अब C ++ 11 और C ++ 14 मानक हैं, और क्षितिज पर C ++ 17)।
C ++ 14 के अनुसार NaN-ness के लिए जाँच करने के मुख्य तरीके हैं:
std::isnan(value) )
C ++ 11 के बाद से इरादा मानक पुस्तकालय तरीका है। isnan
जाहिरा तौर पर एक ही नाम के Posix मैक्रो के साथ संघर्ष, लेकिन व्यवहार में एक समस्या नहीं है। मुख्य समस्या यह है कि जब फ़्लोटिंग पॉइंट अंकगणितीय अनुकूलन का अनुरोध किया जाता है, तो कम से कम एक मुख्य संकलक, अर्थात् g ++ के साथ, NaN तर्क के लिए std::isnan
लौटता false
है ।
(fpclassify(value) == FP_NAN) )
एक ही समस्या से पीड़ित के रूप में std::isnan
, यानी, विश्वसनीय नहीं है।
(value != value) )
कई SO उत्तरों में अनुशंसित। एक ही समस्या से पीड़ित के रूप में std::isnan
, यानी, विश्वसनीय नहीं है।
(value == Fp_info::quiet_NaN()) )
यह एक ऐसा परीक्षण है जिसमें मानक व्यवहार के साथ NaN का पता नहीं लगाना चाहिए, लेकिन यह कि अनुकूलित व्यवहार के साथ शायद NaN का पता लगा सकते हैं (अनुकूलित कोड के कारण सीधे बिटलेवल निरूपण की तुलना कर सकते हैं), और शायद मानक अन-अनुकूलित व्यवहार को कवर करने के लिए किसी अन्य तरीके के साथ संयुक्त। , दृढ़ता से NaN का पता लगा सकता है। दुर्भाग्य से यह मज़बूती से काम नहीं करने के लिए निकला।
(ilogb(value) == FP_ILOGBNAN) )
एक ही समस्या से पीड़ित के रूप में std::isnan
, यानी, विश्वसनीय नहीं है।
isunordered(1.2345, value) )
एक ही समस्या से पीड़ित के रूप में std::isnan
, यानी, विश्वसनीय नहीं है।
is_ieee754_nan( value ) )
यह एक मानक कार्य नहीं है। यह IEEE 754 मानक के अनुसार बिट्स की जाँच कर रहा है। यह पूरी तरह से विश्वसनीय है लेकिन कोड कुछ हद तक प्रणाली पर निर्भर है।
निम्नलिखित पूर्ण परीक्षण कोड में "सफलता" है कि क्या एक अभिव्यक्ति मूल्य के नेन-नेस की रिपोर्ट करती है। अधिकांश अभिव्यक्तियों के लिए सफलता का यह उपाय, NaN और केवल NaN का पता लगाने का लक्ष्य, उनके मानक शब्दार्थ से मेल खाता है। के लिए (value == Fp_info::quiet_NaN()) )
अभिव्यक्ति, तथापि, मानक व्यवहार है कि यह एक NaN-डिटेक्टर के रूप में काम नहीं करता है।
#include <cmath> // std::isnan, std::fpclassify
#include <iostream>
#include <iomanip> // std::setw
#include <limits>
#include <limits.h> // CHAR_BIT
#include <sstream>
#include <stdint.h> // uint64_t
using namespace std;
#define TEST( x, expr, expected ) \
[&](){ \
const auto value = x; \
const bool result = expr; \
ostringstream stream; \
stream << boolalpha << #x " = " << x << ", (" #expr ") = " << result; \
cout \
<< setw( 60 ) << stream.str() << " " \
<< (result == expected? "Success" : "FAILED") \
<< endl; \
}()
#define TEST_ALL_VARIABLES( expression ) \
TEST( v, expression, true ); \
TEST( u, expression, false ); \
TEST( w, expression, false )
using Fp_info = numeric_limits<double>;
inline auto is_ieee754_nan( double const x )
-> bool
{
static constexpr bool is_claimed_ieee754 = Fp_info::is_iec559;
static constexpr int n_bits_per_byte = CHAR_BIT;
using Byte = unsigned char;
static_assert( is_claimed_ieee754, "!" );
static_assert( n_bits_per_byte == 8, "!" );
static_assert( sizeof( x ) == sizeof( uint64_t ), "!" );
#ifdef _MSC_VER
uint64_t const bits = reinterpret_cast<uint64_t const&>( x );
#else
Byte bytes[sizeof(x)];
memcpy( bytes, &x, sizeof( x ) );
uint64_t int_value;
memcpy( &int_value, bytes, sizeof( x ) );
uint64_t const& bits = int_value;
#endif
static constexpr uint64_t sign_mask = 0x8000000000000000;
static constexpr uint64_t exp_mask = 0x7FF0000000000000;
static constexpr uint64_t mantissa_mask = 0x000FFFFFFFFFFFFF;
(void) sign_mask;
return (bits & exp_mask) == exp_mask and (bits & mantissa_mask) != 0;
}
auto main()
-> int
{
double const v = Fp_info::quiet_NaN();
double const u = 3.14;
double const w = Fp_info::infinity();
cout << boolalpha << left;
cout << "Compiler claims IEEE 754 = " << Fp_info::is_iec559 << endl;
cout << endl;;
TEST_ALL_VARIABLES( std::isnan(value) ); cout << endl;
TEST_ALL_VARIABLES( (fpclassify(value) == FP_NAN) ); cout << endl;
TEST_ALL_VARIABLES( (value != value) ); cout << endl;
TEST_ALL_VARIABLES( (value == Fp_info::quiet_NaN()) ); cout << endl;
TEST_ALL_VARIABLES( (ilogb(value) == FP_ILOGBNAN) ); cout << endl;
TEST_ALL_VARIABLES( isunordered(1.2345, value) ); cout << endl;
TEST_ALL_VARIABLES( is_ieee754_nan( value ) );
}
जी ++ के साथ परिणाम (ध्यान दें कि फिर से मानक व्यवहार (value == Fp_info::quiet_NaN())
यह है कि यह NaN-डिटेक्टर के रूप में काम नहीं करता है, यह सिर्फ व्यावहारिक हित के बहुत अधिक है):
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> g ++ --version | "++" ढूंढें
g ++ (x86_64-win32-sjlj-Rev1, मिनगॉ-डब्ल्यू 64 परियोजना द्वारा निर्मित) 6.3.0
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> g ++ foo.cpp && a
कंपाइलर IEEE 754 = सत्य का दावा करता है
v = nan, (std :: isnan (value)) = सच्ची सफलता
u = 3.14, (std :: isnan (value)) = झूठी सफलता
w = inf, (std :: isnan (value)) = झूठी सफलता
v = nan, ((fpclassify (मान) == 0x0100)) = सच्ची सफलता
u = 3.14, ((fpclassify (मान) == 0x0100)) = झूठी सफलता
w = inf, ((fpclassify (value) == 0x0100)) = false सफलता
v = nan, ((value! = value) = true सफलता
u = 3.14, (मान! = मान) = झूठी सफलता
w = inf, ((value! = value) = false सफलता
v = nan, ((value == Fp_info :: शांत_NaN ())) = झूठी विफल
u = 3.14, (मान == Fp_info :: शांत_NaN ())) = झूठी सफलता
w = inf, ((value == Fp_info :: शांत_NaN ())) = झूठी सफलता
v = nan, ((ilogb (value) == ((int) 0x80000000)) = true सफलता
u = 3.14, ((ilogb (value) == ((int) 0x80000000))) = झूठी सफलता
w = inf, ((ilogb (value) == ((int) 0x80000000)) = false सफलता
v = nan, (isunordered (1.2345, मान)) = सच्ची सफलता
u = 3.14, (isunordered (1.2345, मान)) = झूठी सफलता
w = inf, (isunordered (1.2345, मान)) = झूठी सफलता
v = nan, (is_ieee754_nan (मान)) = सच्ची सफलता
u = 3.14, (is_ieee754_nan (मान)) = झूठी सफलता
w = inf, (is_ieee754_nan (मान)) = झूठी सफलता
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> g ++ foo.cpp -ffast-math && a
कंपाइलर IEEE 754 = सत्य का दावा करता है
v = nan, (std :: isnan (value)) = false FAILED
u = 3.14, (std :: isnan (value)) = झूठी सफलता
w = inf, (std :: isnan (value)) = झूठी सफलता
v = nan, ((fpclassify (value) == 0x0100)) = false FAILED
u = 3.14, ((fpclassify (मान) == 0x0100)) = झूठी सफलता
w = inf, ((fpclassify (value) == 0x0100)) = false सफलता
v = nan, ((value! = value) = false FAILED
u = 3.14, (मान! = मान) = झूठी सफलता
w = inf, ((value! = value) = false सफलता
v = nan, ((value == Fp_info :: शांत_NaN ())) = सच्ची सफलता
u = 3.14, (मान == Fp_info :: शांत_NaN ())) = सच विफल
w = inf, ((value == Fp_info :: शांत_NaN ())) = सच विफल
v = nan, ((ilogb (value) == ((int) 0x80000000)) = true सफलता
u = 3.14, ((ilogb (value) == ((int) 0x80000000))) = झूठी सफलता
w = inf, ((ilogb (value) == ((int) 0x80000000)) = false सफलता
v = nan, (isunordered (1.2345, मान)) = झूठी विफल
u = 3.14, (isunordered (1.2345, मान)) = झूठी सफलता
w = inf, (isunordered (1.2345, मान)) = झूठी सफलता
v = nan, (is_ieee754_nan (मान)) = सच्ची सफलता
u = 3.14, (is_ieee754_nan (मान)) = झूठी सफलता
w = inf, (is_ieee754_nan (मान)) = झूठी सफलता
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> _
दृश्य C ++ के परिणाम:
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> cl / nologo- 2> & 1 | "++" ढूंढें
Microsoft (R) C / C ++ का कंपाइलिंग वर्जन 19.00.23725 x86 के लिए
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> cl foo.cpp / Feb && b
foo.cpp
कंपाइलर IEEE 754 = सत्य का दावा करता है
v = nan, (std :: isnan (value)) = सच्ची सफलता
u = 3.14, (std :: isnan (value)) = झूठी सफलता
w = inf, (std :: isnan (value)) = झूठी सफलता
v = nan, ((fpclassify (value) == 2)) = true सफलता
u = 3.14, (fpclassify (value) == 2)) = false सफलता
w = inf, ((fpclassify (value) == 2) = झूठी सफलता
v = nan, ((value! = value) = true सफलता
u = 3.14, (मान! = मान) = झूठी सफलता
w = inf, ((value! = value) = false सफलता
v = nan, ((value == Fp_info :: शांत_NaN ())) = झूठी विफल
u = 3.14, (मान == Fp_info :: शांत_NaN ())) = झूठी सफलता
w = inf, ((value == Fp_info :: शांत_NaN ())) = झूठी सफलता
v = nan, ((ilogb (value) == 0x7fffffff)) = सच्ची सफलता
u = 3.14, (ilogb (मान) == 0x7fffffff)) = झूठी सफलता
w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered (1.2345, मान)) = सच्ची सफलता
u = 3.14, (isunordered (1.2345, मान)) = झूठी सफलता
w = inf, (isunordered (1.2345, मान)) = झूठी सफलता
v = nan, (is_ieee754_nan (मान)) = सच्ची सफलता
u = 3.14, (is_ieee754_nan (मान)) = झूठी सफलता
w = inf, (is_ieee754_nan (मान)) = झूठी सफलता
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> सीएल foo.cpp / Feb / fp: fast && b
foo.cpp
कंपाइलर IEEE 754 = सत्य का दावा करता है
v = nan, (std :: isnan (value)) = सच्ची सफलता
u = 3.14, (std :: isnan (value)) = झूठी सफलता
w = inf, (std :: isnan (value)) = झूठी सफलता
v = nan, ((fpclassify (value) == 2)) = true सफलता
u = 3.14, (fpclassify (value) == 2)) = false सफलता
w = inf, ((fpclassify (value) == 2) = झूठी सफलता
v = nan, ((value! = value) = true सफलता
u = 3.14, (मान! = मान) = झूठी सफलता
w = inf, ((value! = value) = false सफलता
v = nan, ((value == Fp_info :: शांत_NaN ())) = झूठी विफल
u = 3.14, (मान == Fp_info :: शांत_NaN ())) = झूठी सफलता
w = inf, ((value == Fp_info :: शांत_NaN ())) = झूठी सफलता
v = nan, ((ilogb (value) == 0x7fffffff)) = सच्ची सफलता
u = 3.14, (ilogb (मान) == 0x7fffffff)) = झूठी सफलता
w = inf, ((ilogb (value) == 0x7fffffff)) = true FAILED
v = nan, (isunordered (1.2345, मान)) = सच्ची सफलता
u = 3.14, (isunordered (1.2345, मान)) = झूठी सफलता
w = inf, (isunordered (1.2345, मान)) = झूठी सफलता
v = nan, (is_ieee754_nan (मान)) = सच्ची सफलता
u = 3.14, (is_ieee754_nan (मान)) = झूठी सफलता
w = inf, (is_ieee754_nan (मान)) = झूठी सफलता
[C: \ my \ forum \ so \ 282 (NaN का पता लगाएं)]
> _
उपरोक्त परिणामों को सारांशित करते हुए, is_ieee754_nan
इस परीक्षण कार्यक्रम में परिभाषित फ़ंक्शन का उपयोग करते हुए, बिट-स्तरीय प्रतिनिधित्व का केवल प्रत्यक्ष परीक्षण, जी + और विज़ुअल सी ++ दोनों के साथ सभी मामलों में मज़बूती से काम करता है।
परिशिष्ट:
उपरोक्त पोस्ट करने के बाद मैं NaN के लिए परीक्षण करने के लिए अभी तक एक और संभावित के बारे में अवगत हो गया, जिसका उल्लेख यहां एक अन्य उत्तर में किया गया है ((value < 0) == (value >= 0))
। यह दृश्य C ++ के साथ ठीक काम करने के लिए निकला, लेकिन g ++ के -ffast-math
विकल्प के साथ विफल रहा । केवल प्रत्यक्ष बिटपैटन परीक्षण मज़बूती से काम करता है।