शांत NaN और सिग्नलिंग NaN में क्या अंतर है?


98

मैंने फ्लोटिंग-पॉइंट के बारे में पढ़ा है और मैं समझता हूं कि NaN ऑपरेशंस के परिणामस्वरूप हो सकता है। लेकिन मैं समझ नहीं पा रहा हूं कि ये अवधारणाएं वास्तव में क्या हैं। उनके बीच क्या अंतर है?

C ++ प्रोग्रामिंग के दौरान कौन सा उत्पादन किया जा सकता है? एक प्रोग्रामर के रूप में, क्या मैं एक प्रोग्राम लिख सकता हूं जो sNaN का कारण बनता है?

जवाबों:


68

जब एक ऑपरेशन एक शांत NaN में परिणत होता है, तो कोई संकेत नहीं है कि कुछ भी असामान्य है जब तक कि कार्यक्रम परिणाम की जांच नहीं करता है और एक NaN देखता है। यानी फ्लोटिंग-पॉइंट यूनिट (FPU) या लाइब्रेरी से किसी भी सिग्नल के बिना कंप्यूटर में फ्लोटिंग-पॉइंट लागू होने पर गणना जारी रहती है। एक संकेतन NaN एक संकेत उत्पन्न करेगा, आमतौर पर FPU से अपवाद के रूप में। क्या अपवाद फेंका गया है यह एफपीयू की स्थिति पर निर्भर करता है।

C ++ 11 फ्लोटिंग-पॉइंट वातावरण पर कुछ भाषा नियंत्रण जोड़ता है और NaN के लिए बनाने और परीक्षण करने के लिए मानकीकृत तरीके प्रदान करता है । हालाँकि, क्या नियंत्रण लागू किया गया है, अच्छी तरह से मानकीकृत नहीं है और फ्लोटिंग-पॉइंट अपवाद आमतौर पर मानक C ++ अपवादों के समान नहीं पकड़े जाते हैं।

POSIX / Unix सिस्टम में, अस्थायी बिंदु अपवादों को आमतौर पर SIGFPE के लिए हैंडलर का उपयोग करते हुए पकड़ा जाता है


34
इसे जोड़ना: आम तौर पर, सिग्नलिंग NaN (sNaN) का उद्देश्य डिबगिंग के लिए है। उदाहरण के लिए, फ्लोटिंग-पॉइंट ऑब्जेक्ट्स को sNaN के लिए इनिशियलाइज़ किया जा सकता है। फिर, यदि प्रोग्राम का उपयोग करने से पहले उनमें से एक मान में विफल रहता है, तो अपवाद तब होगा जब प्रोग्राम एक अंकगणितीय ऑपरेशन में sNaN का उपयोग करता है। एक कार्यक्रम अनजाने में एक sNaN का उत्पादन नहीं करेगा; कोई सामान्य ऑपरेशन sNaNs उत्पन्न नहीं करता है। वे केवल विशेष रूप से एक संकेतन NaN होने के उद्देश्य से बनाए गए हैं, न कि किसी अंकगणित के परिणाम के रूप में।
एरिक पोस्टपिसिल

18
इसके विपरीत, NaN अधिक सामान्य प्रोग्रामिंग के लिए हैं। जब कोई संख्यात्मक परिणाम नहीं होता है, तो वे सामान्य ऑपरेशन द्वारा उत्पादित किए जा सकते हैं (उदाहरण के लिए, एक ऋणात्मक संख्या के वर्गमूल को लेना जब परिणाम वास्तविक होना चाहिए)। उनका उद्देश्य आम तौर पर अंकगणित को कुछ हद तक आगे बढ़ने की अनुमति देना है। उदाहरण के लिए, आपके पास संख्याओं की एक विशाल सरणी हो सकती है, जिनमें से कुछ विशेष मामलों का प्रतिनिधित्व करती हैं जिन्हें सामान्य रूप से नियंत्रित नहीं किया जा सकता है। आप इस सरणी को संसाधित करने के लिए एक जटिल फ़ंक्शन को कॉल कर सकते हैं, और यह NaNs की अनदेखी करते हुए सामान्य अंकगणित के साथ सरणी पर काम कर सकता है। इसके समाप्त होने के बाद, आप विशेष मामलों को अधिक कार्य के लिए अलग कर देंगे।
एरिक पोस्टपिसिल

@wrdieter धन्यवाद, तब केवल नाज़र अंतर ही एक्साइटेशन पैदा कर रहा है या नहीं।
जलालजेरी

@ EricPostpischil प्रश्न के दूसरे टुकड़े पर आपका ध्यान देने के लिए धन्यवाद।
जलालजेरी

@ जजलजबरी हां, अपवाद मुख्य अंतर है
लेखक

36

प्रायोगिक तौर पर qNaN और sNaN कैसे दिखते हैं?

आइए पहले जानें कि अगर हमारे पास sNaN या qNaN है तो कैसे पहचानें।

मैं C के बजाय इस उत्तर में C ++ का उपयोग करूंगा क्योंकि यह सुविधाजनक प्रदान करता है std::numeric_limits::quiet_NaNऔर std::numeric_limits::signaling_NaNजो मुझे C में आसानी से नहीं मिला।

मैं तब भी यह पता लगाने के लिए फ़ंक्शन नहीं कर सकता था कि कोई NaN sNaN या qNaN है, तो चलिए NaN कच्चे बाइट को प्रिंट करते हैं:

main.cpp

#include <cassert>
#include <cstring>
#include <cmath> // nanf, isnan
#include <iostream>
#include <limits> // std::numeric_limits

#pragma STDC FENV_ACCESS ON

void print_float(float f) {
    std::uint32_t i;
    std::memcpy(&i, &f, sizeof f);
    std::cout << std::hex << i << std::endl;
}

int main() {
    static_assert(std::numeric_limits<float>::has_quiet_NaN, "");
    static_assert(std::numeric_limits<float>::has_signaling_NaN, "");
    static_assert(std::numeric_limits<float>::has_infinity, "");

    // Generate them.
    float qnan = std::numeric_limits<float>::quiet_NaN();
    float snan = std::numeric_limits<float>::signaling_NaN();
    float inf = std::numeric_limits<float>::infinity();
    float nan0 = std::nanf("0");
    float nan1 = std::nanf("1");
    float nan2 = std::nanf("2");
    float div_0_0 = 0.0f / 0.0f;
    float sqrt_negative = std::sqrt(-1.0f);

    // Print their bytes.
    std::cout << "qnan "; print_float(qnan);
    std::cout << "snan "; print_float(snan);
    std::cout << " inf "; print_float(inf);
    std::cout << "-inf "; print_float(-inf);
    std::cout << "nan0 "; print_float(nan0);
    std::cout << "nan1 "; print_float(nan1);
    std::cout << "nan2 "; print_float(nan2);
    std::cout << " 0/0 "; print_float(div_0_0);
    std::cout << "sqrt "; print_float(sqrt_negative);

    // Assert if they are NaN or not.
    assert(std::isnan(qnan));
    assert(std::isnan(snan));
    assert(!std::isnan(inf));
    assert(!std::isnan(-inf));
    assert(std::isnan(nan0));
    assert(std::isnan(nan1));
    assert(std::isnan(nan2));
    assert(std::isnan(div_0_0));
    assert(std::isnan(sqrt_negative));
}

संकलित करें और चलाएं:

g++ -ggdb3 -O3 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

मेरे x86_64 मशीन पर आउटपुट:

qnan 7fc00000
snan 7fa00000
 inf 7f800000
-inf ff800000
nan0 7fc00000
nan1 7fc00001
nan2 7fc00002
 0/0 ffc00000
sqrt ffc00000

हम QEMU उपयोगकर्ता मोड के साथ anarch64 पर कार्यक्रम को भी निष्पादित कर सकते हैं:

aarch64-linux-gnu-g++ -ggdb3 -O3 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
qemu-aarch64 -L /usr/aarch64-linux-gnu/ main.out

और यह ठीक उसी आउटपुट का उत्पादन करता है, जिसमें सुझाव दिया गया है कि कई आर्क बारीकी से IEEE 754 को लागू करते हैं।

इस बिंदु पर, यदि आप IEEE 754 फ़्लोटिंग पॉइंट नंबरों की संरचना से परिचित नहीं हैं, तो एक नज़र डालें: सबऑनॉर्मल फ़्लोटिंग पॉइंट संख्या क्या है?

बाइनरी में कुछ मान ऊपर हैं:

     31
     |
     | 30    23 22                    0
     | |      | |                     |
-----+-+------+-+---------------------+
qnan 0 11111111 10000000000000000000000
snan 0 11111111 01000000000000000000000
 inf 0 11111111 00000000000000000000000
-inf 1 11111111 00000000000000000000000
-----+-+------+-+---------------------+
     | |      | |                     |
     | +------+ +---------------------+
     |    |               |
     |    v               v
     | exponent        fraction
     |
     v
     sign

इस प्रयोग से हम मानते हैं कि:

  • qNaN और sNaN केवल 22: 1 का अर्थ है कि शांत का मतलब विभेदित प्रतीत होता है, और 0 का अर्थ है सिग्नलिंग

  • शिशु भी घातांक == 0xFF के साथ काफी समान हैं, लेकिन उनके पास अंश == 0 है।

    इस कारण से, NaN को 21 से 1 सेट करना होगा, अन्यथा sNaN को सकारात्मक अनंतता से अलग करना संभव नहीं होगा!

  • nanf() कई अलग-अलग NaN का उत्पादन करता है, इसलिए कई संभावित एनकोडिंग होने चाहिए:

    7fc00000
    7fc00001
    7fc00002
    

    चूंकि nan0जैसा है std::numeric_limits<float>::quiet_NaN(), हम वैसा ही करते हैं कि वे सभी अलग-अलग शांत NaN हैं।

    C11 N1570 मानक प्रारूप पुष्टि की है कि nanf()शांत Nans उत्पन्न करता है, क्योंकि nanfआगे खेलने strtodऔर 7.22.1.3 "strtod, strtof, और strtold कार्यों" का कहना है:

    एक चरित्र अनुक्रम एनएएन या एनएएन (एन-चार-सीक्वेंस ऑप्ट) की व्याख्या एक शांत एनएन के रूप में की जाती है, यदि रिटर्न प्रकार में समर्थित है, और एक विषय अनुक्रम भाग की तरह है जिसमें अपेक्षित रूप नहीं है; एन-चार अनुक्रम का अर्थ कार्यान्वयन-परिभाषित है। 293)

यह सभी देखें:

मैनुअल में qNaNs और sNaNs कैसे दिखते हैं?

IEEE 754 2008 की अनुशंसा है कि (TODO अनिवार्य या वैकल्पिक?):

  • घातांक == 0xFF और अंश के साथ कुछ भी! = 0 एक NaN है
  • और यह कि उच्चतम अंश बिट sNaN से qNaN को अलग करता है

लेकिन यह कहना मुनासिब नहीं है कि कौन सा बिट एनएएन से अनंत को अलग करना पसंद करता है।

6.2.1 "द्विआधारी स्वरूपों में NaN एन्कोडिंग" कहते हैं:

जब वे संचालन के परिणाम होते हैं, तो यह उपखंड आगे NaNs के एन्कोडिंग्स को थोड़ा सा तार के रूप में निर्दिष्ट करता है। जब एन्कोड किया जाता है, तो सभी NaN में एक NaN के रूप में एन्कोडिंग की पहचान करने के लिए साइन बिट और बिट्स का एक पैटर्न होता है और जो इसकी तरह (sNaN बनाम qNaN) को निर्धारित करता है। शेष बिट्स, जो अनुगामी क्षेत्र में हैं, पेलोड को एनकोड करते हैं, जो नैदानिक ​​जानकारी हो सकती है (ऊपर देखें)। 34

सभी बाइनरी NaN बिट स्ट्रिंग्स में पक्षपाती प्रतिपादक क्षेत्र E के सभी बिट्स 1 से सेट होते हैं (3.4 देखें)। एक शांत NaN बिट स्ट्रिंग अनुगामी क्षेत्र क्षेत्र T जा रहा है की पहली बिट (d1) के साथ एन्कोडेड होना चाहिए। एक संकेतन NaN बिट स्ट्रिंग अनुगामी महत्व क्षेत्र के पहले बिट के साथ एन्कोड किया जाना चाहिए 0. यदि पहला बिट अनुगामी महत्त्वपूर्ण क्षेत्र 0 है, अनुगामी महत्त्वपूर्ण क्षेत्र का कुछ और हिस्सा NaN को अनंत से अलग करने के लिए गैर-शून्य होना चाहिए। अभी वर्णित पसंदीदा एन्कोडिंग में, एक संकेतन NaN को D1 से 1 सेट करके शांत किया जाएगा, जिससे T के शेष बिट्स अपरिवर्तित रहेंगे। द्विआधारी प्रारूपों के लिए, पेलोड को पीछे के क्षेत्र में p significant 2 कम से कम महत्वपूर्ण बिट्स में एन्कोड किया गया है

इंटेल 64 और IA-32 आर्किटेक्चर सॉफ्टवेयर डेवलपर की मैनुअल - खंड 1 बेसिक वास्तुकला - 253665-056US सितंबर 2015 4.8.3.4 "Nans" पुष्टि की है कि 86 उच्चतम अंश थोड़ा करके NaN और स्नान भेद द्वारा आईईईई 754 इस प्रकार है:

IA-32 आर्किटेक्चर NaNs के दो वर्गों को परिभाषित करता है: शांत NaN (QNaNs) और NaN (SNaN) को सिग्नल करना। QNaN एक NaN है जिसमें सबसे महत्वपूर्ण अंश बिट सेट है SNNN एक NaN है जिसमें सबसे महत्वपूर्ण अंश बिट स्पष्ट है।

और ऐसा ही एआरएम आर्किटेक्चर रेफरेंस मैनुअल - ARMv8, ARMv8-A आर्किटेक्चर प्रोफाइल के लिए है - DDI 0487C.a A1.4.3 "एकल-सटीक फ़्लोटिंग-पॉइंट फॉर्मेट":

fraction != 0: मान एक NaN है, और या तो एक शांत NaN या एक संकेतन NaN है। NaN के दो प्रकार उनके सबसे महत्वपूर्ण अंश बिट द्वारा प्रतिष्ठित हैं, बिट [22]:

  • bit[22] == 0: NaN एक संकेतन NaN है। साइन बिट किसी भी मान ले सकता है, और शेष अंश बिट्स सभी शून्य को छोड़कर कोई भी मूल्य ले सकते हैं।
  • bit[22] == 1: NaN एक शांत NaN है। साइन बिट और शेष अंश बिट्स किसी भी मूल्य ले सकते हैं।

QNanS और sNaN कैसे उत्पन्न होते हैं?

QNaN और sNaN के बीच एक बड़ा अंतर यह है कि:

  • qNaN अजीब मूल्यों के साथ नियमित रूप से अंतर्निहित (सॉफ्टवेयर या हार्डवेयर) अंकगणितीय संचालन द्वारा उत्पन्न होता है
  • sNaN बिल्ट-इन ऑपरेशंस द्वारा कभी उत्पन्न नहीं होता है, इसे केवल प्रोग्रामर द्वारा स्पष्ट रूप से जोड़ा जा सकता है, जैसे std::numeric_limits::signaling_NaN

मैं उस के लिए स्पष्ट IEEE 754 या C11 उद्धरण नहीं ढूँढ सका, लेकिन न तो मुझे कोई अंतर्निहित ऑपरेशन मिल सकता है जो sNaNs;;

इंटेल मैनुअल स्पष्ट रूप से 4.8.3.4 "NaNs" पर इस सिद्धांत को बताता है:

SNaN आमतौर पर एक अपवाद हैंडलर को फंसाने या आह्वान करने के लिए उपयोग किया जाता है। उन्हें सॉफ्टवेयर द्वारा डाला जाना चाहिए; अर्थात्, प्रोसेसर कभी भी फ्लोटिंग-पॉइंट ऑपरेशन के परिणामस्वरूप एक SNaN उत्पन्न नहीं करता है।

यह हमारे उदाहरण से देखा जा सकता है जहाँ दोनों:

float div_0_0 = 0.0f / 0.0f;
float sqrt_negative = std::sqrt(-1.0f);

के रूप में बिल्कुल बिट्स का उत्पादन std::numeric_limits<float>::quiet_NaN()

उन दोनों ऑपरेशनों को एक एकल x86 असेंबली इंस्ट्रक्शन में संकलित किया गया है जो सीधे qNaN को हार्डवेयर में उत्पन्न करता है (TODO पुष्टि DB के साथ)।

QNaNs और sNaNs अलग-अलग क्या करते हैं?

अब जब हम जानते हैं कि qNaNs और sNaNs क्या दिखते हैं, और उन्हें कैसे हेरफेर करना है, तो हम आखिरकार कोशिश करते हैं और sNaNs अपनी बात करने और कुछ कार्यक्रमों को उड़ाने के लिए तैयार हैं!

तो आगे की हलचल के बिना:

blow_up.cpp

#include <cassert>
#include <cfenv>
#include <cmath> // isnan
#include <iostream>
#include <limits> // std::numeric_limits
#include <unistd.h>

#pragma STDC FENV_ACCESS ON

int main() {
    float snan = std::numeric_limits<float>::signaling_NaN();
    float qnan = std::numeric_limits<float>::quiet_NaN();
    float f;

    // No exceptions.
    assert(std::fetestexcept(FE_ALL_EXCEPT) == 0);

    // Still no exceptions because qNaN.
    f = qnan + 1.0f;
    assert(std::isnan(f));
    if (std::fetestexcept(FE_ALL_EXCEPT) == FE_INVALID)
        std::cout << "FE_ALL_EXCEPT qnan + 1.0f" << std::endl;

    // Now we can get an exception because sNaN, but signals are disabled.
    f = snan + 1.0f;
    assert(std::isnan(f));
    if (std::fetestexcept(FE_ALL_EXCEPT) == FE_INVALID)
        std::cout << "FE_ALL_EXCEPT snan + 1.0f" << std::endl;
    feclearexcept(FE_ALL_EXCEPT);

    // And now we enable signals and blow up with SIGFPE! >:-)
    feenableexcept(FE_INVALID);
    f = qnan + 1.0f;
    std::cout << "feenableexcept qnan + 1.0f" << std::endl;
    f = snan + 1.0f;
    std::cout << "feenableexcept snan + 1.0f" << std::endl;
}

संकलित करें, चलाएँ और बाहर निकलने की स्थिति प्राप्त करें:

g++ -ggdb3 -O0 -Wall -Wextra -pthread -std=c++11 -pedantic-errors -o blow_up.out blow_up.cpp -lm -lrt
./blow_up.out
echo $?

आउटपुट:

FE_ALL_EXCEPT snan + 1.0f
feenableexcept qnan + 1.0f
Floating point exception (core dumped)
136

ध्यान दें कि यह व्यवहार केवल -O0GCC 8.2 में होता है : के साथ-O3 GCC पूर्व-गणना करता है और हमारे सभी sNaN परिचालनों का अनुकूलन करता है! मुझे यकीन नहीं है कि अगर इसे रोकने का एक मानक अनुपालन तरीका है।

तो हम इस उदाहरण से कटौती करते हैं:

  • snan + 1.0कारण है FE_INVALID, लेकिन qnan + 1.0नहीं है

  • यदि यह सक्षम है तो लिनक्स केवल एक संकेत उत्पन्न करता है feenableexept

    यह एक शानदार विस्तार है, मुझे किसी भी मानक में ऐसा करने का कोई तरीका नहीं मिला।

जब सिग्नल होता है, तो ऐसा इसलिए होता है क्योंकि सीपीयू हार्डवेयर खुद एक अपवाद उठाता है, जिसे लिनक्स कर्नेल ने संभाला और सिग्नल के माध्यम से एप्लिकेशन को सूचित किया।

इसका परिणाम यह है कि बैश प्रिंट Floating point exception (core dumped), और बाहर निकलने की स्थिति है 136, जो सिग्नल से मेल खाती है136 - 128 == 8 , जो निम्नानुसार है:

man 7 signal

है SIGFPE

ध्यान दें कि SIGFPEवही संकेत है जो हमें मिलता है यदि हम 0 से पूर्णांक को विभाजित करने का प्रयास करते हैं:

int main() {
    int i = 1 / 0;
}

पूर्णांकों के लिए हालांकि:

  • शून्य से कुछ भी विभाजित करना संकेत को बढ़ाता है, क्योंकि पूर्णांक में कोई अनंत प्रतिनिधित्व नहीं है
  • संकेत यह डिफ़ॉल्ट रूप से होता है, बिना आवश्यकता के feenableexcept

SIGFPE को कैसे संभालना है?

यदि आप केवल एक हैंडलर बनाते हैं जो सामान्य रूप से लौटता है, तो यह एक अनंत लूप की ओर जाता है, क्योंकि हैंडलर के वापस आने के बाद, विभाजन फिर से होता है! इसे GDB के साथ सत्यापित किया जा सकता है।

इसका एक ही तरीका है कि कहीं और इस्तेमाल किया जाए setjmpऔर longjmpजैसा कि दिखाया गया है: C हैंडल सिग्नल SIGFPE और निष्पादन जारी रखें

SNaNs के कुछ वास्तविक विश्व अनुप्रयोग क्या हैं?

बहुत ईमानदारी से, मैं अभी भी sNaNs के लिए एक सुपर उपयोगी उपयोग के मामले को नहीं समझ पाया हूं, यह पूछा गया है: NaN को संकेत देने की उपयोगिता?

sNaNs विशेष रूप से बेकार महसूस करते हैं क्योंकि हम प्रारंभिक अमान्य संचालन ( 0.0f/0.0f) का पता लगा सकते हैं जो qNaNs के साथ उत्पन्न feenableexceptहोता है: ऐसा प्रतीत होता है कि snanबस अधिक संचालन के लिए त्रुटियों को उठाता है जो qnanइसके लिए नहीं उठाता है, जैसे (qnan + 1.0f )।

उदाहरण के लिए:

main.c

#define _GNU_SOURCE
#include <fenv.h>
#include <stdio.h>

int main(int argc, char **argv) {
    (void)argv;
    float f0 = 0.0;

    if (argc == 1) {
        feenableexcept(FE_INVALID);
    }
    float f1 = 0.0 / f0;
    printf("f1 %f\n", f1);

    feenableexcept(FE_INVALID);
    float f2 = f1 + 1.0;
    printf("f2 %f\n", f2);
}

संकलन:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c -lm

फिर:

./main.out

देता है:

Floating point exception (core dumped)

तथा:

./main.out  1

देता है:

f1 -nan
f2 -nan

इसे भी देखें: C ++ में NaN का पता कैसे लगाएं

सिग्नल फ्लैग क्या हैं और उन्हें कैसे हेरफेर किया जाता है?

सब कुछ सीपीयू हार्डवेयर में लागू किया गया है।

झंडे कुछ रजिस्टर में रहते हैं, और यदि ऐसा कुछ होता है, तो अपवाद / संकेत उठाया जाना चाहिए।

वे रजिस्टर अधिकांश आर्क से उपयोगकर्तालैंड से सुलभ हैं ।

ग्लिब 2.29 कोड का यह हिस्सा वास्तव में समझने में बहुत आसान है!

उदाहरण के लिए, fetestexceptx86_86 के लिए sysdeps / x86_64 / fpu / ftestexcept.c पर लागू किया जाता है :

#include <fenv.h>

int
fetestexcept (int excepts)
{
  int temp;
  unsigned int mxscr;

  /* Get current exceptions.  */
  __asm__ ("fnstsw %0\n"
       "stmxcsr %1" : "=m" (*&temp), "=m" (*&mxscr));

  return (temp | mxscr) & excepts & FE_ALL_EXCEPT;
}
libm_hidden_def (fetestexcept)

इसलिए हम तुरंत देखते हैं कि निर्देशों का उपयोग है stmxcsr "स्टोर MXCSR रजिस्टर स्टेट" के लिए है।

और sysdeps / x86_64 / fpu / feenablxcpt.cfeenableexcept पर लागू किया गया है :

#include <fenv.h>

int
feenableexcept (int excepts)
{
  unsigned short int new_exc, old_exc;
  unsigned int new;

  excepts &= FE_ALL_EXCEPT;

  /* Get the current control word of the x87 FPU.  */
  __asm__ ("fstcw %0" : "=m" (*&new_exc));

  old_exc = (~new_exc) & FE_ALL_EXCEPT;

  new_exc &= ~excepts;
  __asm__ ("fldcw %0" : : "m" (*&new_exc));

  /* And now the same for the SSE MXCSR register.  */
  __asm__ ("stmxcsr %0" : "=m" (*&new));

  /* The SSE exception masks are shifted by 7 bits.  */
  new &= ~(excepts << 7);
  __asm__ ("ldmxcsr %0" : : "m" (*&new));

  return old_exc;
}

QNaN बनाम sNaN के बारे में C मानक क्या कहता है?

C11 N1570 मानक प्रारूप स्पष्ट रूप से कहा गया है कि मानक F.2.1 "Infinities, पर हस्ताक्षर किए शून्य, और Nans" में उन दोनों के बीच भेदभाव नहीं करता:

1 यह विनिर्देश संकेतन NaN के व्यवहार को परिभाषित नहीं करता है। यह आमतौर पर शांत NaN को निरूपित करने के लिए NaN शब्द का उपयोग करता है। नान और इन्फिनिटी मैक्रोज़ और नान <math.h>IEC 60559 NaN और शिशुओं के लिए पदनाम प्रदान करते हैं।

उबंटू 18.10, जीसीसी 8.2 में परीक्षण किया गया। गिटहब अपस्ट्रीम:


en.wikipedia.org/wiki/IEEE_754#Interchange_formats बताते हैं कि IEEE-754 केवल सुझाव देता है कि NaNs को संकेत देने के लिए 0 एक अच्छा कार्यान्वयन विकल्प है, एक NaN को शांत करने की अनुमति के बिना इसे एक अनन्तता (महत्व = 0) बनाए बिना। जाहिर है कि यह मानकीकृत नहीं है, हालांकि यह x86 क्या करता है। (और तथ्य यह है कि यह उस महत्व का MSB है जो qNaN बनाम sNaN को मानकीकृत करता है)। en.wikipedia.org/wiki/Single-preaches_floating-point_format का कहना है कि x86 और ARM समान हैं, लेकिन PA-RISC ने इसके विपरीत चुनाव किया।
पीटर कॉर्ड्स

@PeterCordes हां, मुझे यकीन नहीं है कि IEEE 754 20at में "क्या" == "चाहिए" या "पसंद किया गया है" एक सिग्नलिंग NaN बिट स्ट्रिंग को पीछे की ओर के महत्वपूर्ण क्षेत्र 0 के पहले बिट के साथ एनकोड किया जाना चाहिए।
सिरो सेंटिल्ली 郝海东 冠状 iro i

पुनः: लेकिन यह निर्दिष्ट करने के लिए प्रतीत नहीं होता है कि किस बिट का उपयोग NaN से अनंत को अलग करने के लिए किया जाना चाहिए। आपने लिखा है कि जैसे आपको कुछ विशिष्ट सा होने की उम्मीद थी कि मानक sNaN को अनंत से अलग करने के लिए सेटिंग की सिफारिश करता है। IDK आप ऐसी कोई बिट क्यों होने की उम्मीद करेंगे; कोई भी गैर शून्य विकल्प ठीक है। बस कुछ ऐसा चुनें जो बाद में पहचानता है कि sNaN कहाँ से आया है। आईडीके, बस अजीबोगरीब वाक्यांशों की तरह लगता है, और इसे पढ़ते समय मेरी पहली धारणा यह थी कि आप कह रहे थे कि वेब पेज ने यह नहीं बताया कि एन्कोडिंग में एनएएन से क्या अंतर होता है (एक सर्व-शून्य महत्व)।
पीटर कॉर्ड्स

2008 से पहले, IEEE 754 ने कहा था कि कौन सा सिग्नलिंग / शांत बिट (बिट 22) है, लेकिन कौन सा मूल्य निर्दिष्ट नहीं है। अधिकांश प्रोसेसर 1 = शांत पर परिवर्तित हो गए थे, इसलिए इसे 2008 संस्करण में मानक का हिस्सा बनाया गया था। यह कहता है कि "लागू होना चाहिए" के बजाय "होना चाहिए" पुराने कार्यान्वयन से बचने के लिए जो एक ही विकल्प को गैर-अनुरूप बनाता है। सामान्य तौर पर, "एक मानक अर्थ में" होना चाहिए "जब तक आपके पास बहुत मजबूर (और अधिमानतः अच्छी तरह से प्रलेखित) अनुपालन न करने के कारण हैं"।
जॉन कोवान
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.