अनुकूलन सक्षम करने के साथ अलग फ्लोटिंग पॉइंट परिणाम - संकलक बग?


109

नीचे दिया गया कोड विजुअल स्टूडियो 2008 पर अनुकूलन के साथ और बिना काम करता है। लेकिन यह केवल अनुकूलन (O0) के बिना g ++ पर काम करता है।

#include <cstdlib>
#include <iostream>
#include <cmath>

double round(double v, double digit)
{
    double pow = std::pow(10.0, digit);
    double t = v * pow;
    //std::cout << "t:" << t << std::endl;
    double r = std::floor(t + 0.5);
    //std::cout << "r:" << r << std::endl;
    return r / pow;
}

int main(int argc, char *argv[])
{
    std::cout << round(4.45, 1) << std::endl;
    std::cout << round(4.55, 1) << std::endl;
}

आउटपुट होना चाहिए:

4.5
4.6

लेकिन अनुकूलन ( O1- O3) आउटपुट के साथ g ++ :

4.5
4.5

यदि मैं volatileकीवर्ड को t से पहले जोड़ता हूं , तो यह काम करता है, इसलिए किसी प्रकार का अनुकूलन बग हो सकता है?

G ++ 4.1.2, और 4.4.4 पर परीक्षण करें।

यहाँ ideone पर परिणाम है: http://ideone.com/Rz937

और g ++ पर मेरा परीक्षण आसान है:

g++ -O2 round.cpp

अधिक दिलचस्प परिणाम, यहां तक ​​कि मैं /fp:fastविज़ुअल स्टूडियो 2008 पर विकल्प चालू करता हूं, फिर भी परिणाम सही है।

अगला सवाल:

मैं सोच रहा था, क्या मुझे हमेशा -ffloat-storeविकल्प चालू करना चाहिए ?

क्योंकि मेरे द्वारा परीक्षण किया गया g ++ संस्करण CentOS / Red Hat Linux 5 और CentOS / Redhat 6 के साथ भेज दिया गया है ।

मैंने इन प्लेटफार्मों के तहत अपने कई कार्यक्रमों को संकलित किया है, और मुझे चिंता है कि यह मेरे कार्यक्रमों के अंदर अप्रत्याशित कीड़े पैदा करेगा। मेरे सभी C ++ कोड और उपयोग किए गए पुस्तकालयों की जांच करना थोड़ा मुश्किल लगता है कि क्या उन्हें ऐसी समस्याएं हैं। कोई उपाय?

क्या किसी की भी दिलचस्पी क्यों /fp:fastचालू है, विजुअल स्टूडियो 2008 अभी भी काम करता है? ऐसा लगता है कि दृश्य स्टूडियो 2008 जी ++ की तुलना में इस समस्या पर अधिक विश्वसनीय है?


51
सभी नए SO उपयोगकर्ताओं के लिए: यह है कि आप एक प्रश्न कैसे पूछते हैं। +1
दस सेर

1
FWIW, मुझे MinGW का उपयोग करके g ++ 4.5.0 के साथ सही आउटपुट मिल रहा है।
स्टीव ब्लैकवेल

2
ideone 4.3.4 का उपयोग करता है ideone.com/b8VXg
डैनियल ए। व्हाइट

5
आपको मेरे ध्यान में रखना चाहिए कि आपकी दिनचर्या सभी प्रकार के आउटपुट के साथ मज़बूती से काम करने की संभावना नहीं है। एक पूर्णांक के लिए एक डबल चक्कर लगाने के विपरीत, यह इस तथ्य के लिए कमजोर है कि सभी वास्तविक संख्याओं का प्रतिनिधित्व नहीं किया जा सकता है, इसलिए आपको इस तरह के अधिक बग प्राप्त करने की उम्मीद करनी चाहिए।
जैकब वाइकजोरक

2
उन लोगों के लिए जो बग को पुन: उत्पन्न नहीं कर सकते हैं: डिबग स्टैम्प के बाहर टिप्पणी को अनसुना न करें, वे परिणाम को प्रभावित करते हैं।
एन। 'सर्वनाम' मी।

जवाबों:


91

इंटेल x86 प्रोसेसर आंतरिक रूप से 80-बिट विस्तारित परिशुद्धता का उपयोग करता है, जबकि doubleआम तौर पर 64-बिट चौड़ा होता है। विभिन्न अनुकूलन स्तर प्रभावित करते हैं कि सीपीयू से फ्लोटिंग पॉइंट मान कितनी बार मेमोरी में सेव हो जाते हैं और इस तरह 80-बिट परिशुद्धता से 64-बिट परिशुद्धता तक गोल हो जाते हैं।

-ffloat-storeविभिन्न अनुकूलन स्तरों के साथ समान फ्लोटिंग पॉइंट परिणाम प्राप्त करने के लिए gcc विकल्प का उपयोग करें ।

वैकल्पिक रूप से, long doubleप्रकार का उपयोग करें , जो आमतौर पर 80-बिट से 64-बिट परिशुद्धता तक गोलाई से बचने के लिए जीसीसी पर 80-बिट चौड़ा है।

man gcc यह सब कहता है:

   -ffloat-store
       Do not store floating point variables in registers, and inhibit
       other options that might change whether a floating point value is
       taken from a register or memory.

       This option prevents undesirable excess precision on machines such
       as the 68000 where the floating registers (of the 68881) keep more
       precision than a "double" is supposed to have.  Similarly for the
       x86 architecture.  For most programs, the excess precision does
       only good, but a few programs rely on the precise definition of
       IEEE floating point.  Use -ffloat-store for such programs, after
       modifying them to store all pertinent intermediate computations
       into variables.

X86_64 में बनाता है compilers के लिए SSE रजिस्टरों का उपयोग floatऔर doubleडिफ़ॉल्ट रूप से, ताकि कोई विस्तारित परिशुद्धता प्रयोग किया जाता है और इस मुद्दे को नहीं होती है।

gccसंकलक विकल्प को-mfpmath नियंत्रित करता है।


20
मुझे लगता है कि यह जवाब है। निरंतर 4.55 4.54999999999999 में परिवर्तित हो जाता है जो 64 बिट्स में निकटतम बाइनरी प्रतिनिधित्व है; 10 से गुणा करें और फिर से 64 बिट पर जाएं और आपको 45.5 मिलता है। यदि आप इसे 80-बिट रजिस्टर में रखकर राउंडिंग चरण को छोड़ देते हैं, तो आप 45.4999999999999 पर समाप्त होते हैं।
मार्क रैनसम

धन्यवाद, मैं भी इस विकल्प को नहीं जानता। लेकिन मैं सोच रहा था, क्या मुझे हमेशा -फ्लोट-स्टोर विकल्प चालू करना चाहिए? क्योंकि जिस जी ++ संस्करण का मैंने परीक्षण किया है उसे CentOS / Redhat 5 और CentOS / Redhat 6 के साथ शिप किया गया है। मैंने इन प्लेटफार्मों के तहत अपने कई कार्यक्रमों को संकलित किया है, मुझे इस बात की चिंता है कि मेरे कार्यक्रमों के अंदर अप्रत्याशित बग पैदा हो जाएंगे।
भालू

5
@Bear, डिबग स्टेटमेंट संभवतः मान को एक रजिस्टर से मेमोरी में फ्लश करने का कारण बनता है।
मार्क रैनसम

2
@ ठीक है, आम तौर पर आपके आवेदन को विस्तारित परिशुद्धता से लाभ उठाना चाहिए, जब तक कि यह 64-बिट फ्लोट के नीचे या अतिप्रवाह और उत्पादन की उम्मीद होने पर अत्यंत छोटे या विशाल मूल्यों पर संचालित हो inf। अंगूठे का कोई अच्छा नियम नहीं है, इकाई परीक्षण आपको एक निश्चित उत्तर दे सकते हैं।
मैक्सिम इगोरुस्किन

2
@bear एक सामान्य नियम के रूप में, यदि आपको ऐसे परिणामों की आवश्यकता है जो पूरी तरह से अनुमान लगाने योग्य हैं और / या वास्तव में एक मानव को कागज़ पर क्या करना है तो आपको फ्लोटिंग पॉइंट से बचना चाहिए। -फ्लोट-स्टोर अप्रत्याशितता के एक स्रोत को हटा देता है लेकिन यह एक जादू की गोली नहीं है।
प्लग

10

आउटपुट होना चाहिए: ४.५ ४.४ यह वही है जो आउटपुट तब होगा जब आपके पास असीम परिशुद्धता थी, या यदि आप एक ऐसे उपकरण के साथ काम कर रहे थे जो बाइनरी-आधारित फ्लोटिंग पॉइंट प्रतिनिधित्व के बजाय दशमलव-आधारित का उपयोग करता था। लेकिन, तुम नहीं हो। अधिकांश कंप्यूटर बाइनरी IEEE फ़्लोटिंग पॉइंट मानक का उपयोग करते हैं।

जैसा कि मैक्सिम येगोरुस्किन ने पहले ही अपने जवाब में उल्लेख किया है, समस्या का हिस्सा यह है कि आंतरिक रूप से आपका कंप्यूटर 80 बिट फ्लोटिंग पॉइंट प्रतिनिधित्व का उपयोग कर रहा है। यह समस्या का सिर्फ एक हिस्सा है, हालांकि। समस्या का आधार यह है कि n.nn5 फॉर्म की किसी भी संख्या में एक सटीक बाइनरी फ्लोटिंग प्रतिनिधित्व नहीं है। उन कोने के मामले हमेशा अक्षम संख्या होते हैं।

यदि आप वास्तव में चाहते हैं कि आपकी गोलाई मज़बूती से इन कोने के मामलों को गोल करने में सक्षम हो, तो आपको एक राउंडिंग एल्गोरिथ्म की आवश्यकता है जो इस तथ्य को संबोधित करता है कि n.n5, n.nn5, या n.nn5, आदि (लेकिन n.5 नहीं है) हमेशा अयथार्थ। कोने के मामले का पता लगाएं, जो निर्धारित करता है कि कुछ इनपुट मूल्य ऊपर या नीचे गोल हैं और इस कोने के मामले की तुलना के आधार पर गोल-अप या गोल-डाउन मूल्य वापस करते हैं। और आपको यह ध्यान रखने की ज़रूरत है कि एक अनुकूलन करने वाला कंपाइलर एक विस्तारित सटीक रजिस्टर में उस कोने के मामले को नहीं डालेगा।

देखते हैं कि एक्सेल कैसे बढ़ते हुए होते हुए भी फ्लोटिंग नंबरों को सफलतापूर्वक राउंड करता है? इस तरह के एक एल्गोरिथ्म के लिए।

या आप बस इस तथ्य के साथ रह सकते हैं कि कोने के मामले कभी-कभी गलत तरीके से गोल हो जाएंगे।


6

अलग-अलग कंपाइलरों में अलग-अलग अनुकूलन सेटिंग्स होती हैं। उन तेज़ अनुकूलन सेटिंग्स में से कुछ IEEE 754 के अनुसार सख्त फ़्लोटिंग-पॉइंट नियमों को बनाए नहीं रखती हैं । विजुअल स्टूडियो एक विशिष्ट सेटिंग, है /fp:strict, /fp:precise, /fp:fast, जहां /fp:fastक्या किया जा सकता है पर मानक का उल्लंघन करती है। आप पा सकते हैं कि यह ध्वज ऐसी सेटिंग्स में अनुकूलन को नियंत्रित करता है। आपको GCC में एक समान सेटिंग भी मिल सकती है जो व्यवहार को बदल देती है।

यदि यह मामला है, तो केवल एक चीज जो संकलक के बीच अलग है वह यह है कि जीसीसी उच्च अनुकूलन पर डिफ़ॉल्ट रूप से सबसे तेज फ्लोटिंग पॉइंट व्यवहार की तलाश करेगा, जबकि विज़ुअल स्टूडियो उच्च अनुकूलन स्तरों के साथ फ्लोटिंग पॉइंट व्यवहार को नहीं बदलता है। इस प्रकार यह वास्तव में एक वास्तविक बग नहीं हो सकता है, लेकिन एक विकल्प का इरादा व्यवहार जिसे आप नहीं जानते थे कि आप चालू कर रहे हैं।


4
-ffast-mathGCC के लिए एक स्विच है, और यह -Oउद्धरण के बाद से किसी भी अनुकूलन स्तर से चालू नहीं होता है : "यह उन कार्यक्रमों के लिए गलत आउटपुट में परिणाम कर सकता है जो IEEE या ISO नियमों / गणित कार्यों के विनिर्देशों के सटीक कार्यान्वयन पर निर्भर करते हैं।"
Mat

@Mat: मैंने कोशिश की है -ffast-mathऔर कुछ और चीजें मेरे g++ 4.4.3और मैं अभी भी समस्या को दोहराने में असमर्थ हूं।
एनपीई

अच्छा: -ffast-mathमैं 4.5अनुकूलन के स्तर से अधिक के लिए दोनों मामलों में मिलता है 0
केरेक एसबी

: (सुधार मैं 4.5के साथ -O1और -O2है, लेकिन साथ नहीं -O0और -O3जीसीसी 4.4.3 में है, लेकिन साथ -O1,2,3जीसीसी 4.6.1 में।)
Kerrek एस.बी.

4

उन लोगों के लिए जो बग को पुन: उत्पन्न नहीं कर सकते हैं: डिबग स्टैम्प के बाहर टिप्पणी को अनसुना न करें, वे परिणाम को प्रभावित करते हैं।

इसका तात्पर्य है कि समस्या डिबग स्टेटमेंट से संबंधित है। और ऐसा लगता है कि आउटपुट स्टेटमेंट के दौरान रजिस्टरों में मानों को लोड करने के कारण एक राउंडिंग त्रुटि है, यही वजह है कि अन्य लोगों ने पाया कि आप इसे ठीक कर सकते हैं-ffloat-store

अगला सवाल:

मैं सोच रहा था, क्या मुझे हमेशा -ffloat-storeविकल्प चालू करना चाहिए ?

क्षुद्र हो करने के लिए, वहाँ एक कारण यह है कि कुछ प्रोग्रामर चालू नहीं करते होना चाहिए -ffloat-store, नहीं तो विकल्प मौजूद नहीं हैं (इसी तरह, एक कारण यह है कि कुछ प्रोग्रामर वहाँ होना चाहिए है पर बारी -ffloat-store)। मैं हमेशा इसे चालू करने या हमेशा इसे बंद करने की सलाह नहीं दूंगा। इसे चालू करना कुछ अनुकूलन को रोकता है, लेकिन इसे बंद करने से आप जिस तरह का व्यवहार कर रहे हैं, उसके लिए अनुमति देता है।

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

इसके बजाय, आप उस समस्या के अन्य समाधानों पर गौर करना चाहते हैं जिसे आप हल करने की कोशिश कर रहे हैं (दुर्भाग्य से, कोएनिग वास्तविक कागज की ओर इशारा नहीं करता है, और मैं वास्तव में इसके लिए एक स्पष्ट "विहित" स्थान नहीं पा सकता हूं, इसलिए मैं 'आपको Google को भेजना होगा )।


यदि आप आउटपुट उद्देश्यों के लिए चक्कर नहीं लगा रहे हैं, तो मैं शायद std::modf()(इन cmath) और std::numeric_limits<double>::epsilon()(इन limits) को देखूंगा। मूल round()कार्य के बारे में सोचते हुए , मेरा मानना ​​है कि std::floor(d + .5)इस फ़ंक्शन को कॉल के साथ कॉल को बदलने के लिए क्लीनर होगा :

// this still has the same problems as the original rounding function
int round_up(double d)
{
    // return value will be coerced to int, and truncated as expected
    // you can then assign the int to a double, if desired
    return d + 0.5;
}

मुझे लगता है कि निम्नलिखित सुधार का सुझाव देता है:

// this won't work for negative d ...
// this may still round some numbers up when they should be rounded down
int round_up(double d)
{
    double floor;
    d = std::modf(d, &floor);
    return floor + (d + .5 + std::numeric_limits<double>::epsilon());
}

एक साधारण नोट: std::numeric_limits<T>::epsilon()को "सबसे छोटी संख्या 1 में जोड़ा जाता है जो 1 के बराबर संख्या नहीं बनाता है।" आपको आमतौर पर एक रिश्तेदार एप्सिलॉन (यानी, स्केल एप्सिलॉन का उपयोग किसी भी तरह से इस तथ्य के लिए करना होगा कि आप "1" के अलावा अन्य संख्याओं के साथ काम कर रहे हैं)। का योग d, .5और std::numeric_limits<double>::epsilon()1 के पास होना चाहिए, इसलिए उस समूह को जोड़ना इसका मतलब है कि std::numeric_limits<double>::epsilon()हम जो कर रहे हैं उसके लिए सही आकार के बारे में होगा। यदि कुछ भी हो, std::numeric_limits<double>::epsilon()तो बहुत बड़ा होगा (जब तीनों का योग एक से कम है) और हमें कुछ संख्याओं को गोल करने का कारण बन सकता है जब हमें नहीं करना चाहिए।


आजकल, आपको विचार करना चाहिए std::nearbyint()


एक "सापेक्ष एप्सिलॉन" को 1 ulp (अंतिम स्थान में 1 इकाई) कहा जाता है। x - nextafter(x, INFINITY)एक्स के लिए 1 एलईपी से संबंधित है (लेकिन इसका उपयोग न करें; मुझे यकीन है कि कोने के मामले हैं और मैंने बस इसे बनाया है)। के लिए cppreference उदाहरण के epsilon() पास ULP- आधारित सापेक्ष त्रुटि प्राप्त करने के लिए इसे स्केल करने का एक उदाहरण है
पीटर कॉर्डेस

2
BTW, 2016 का उत्तर -ffloat-storeहै: पहले स्थान पर x87 का उपयोग न करें। SSE2 गणित (64-बिट बायनेरिज़, या -mfpmath=sse -msse2क्रस्टी पुरानी 32-बिट बायनेरी बनाने के लिए) का उपयोग करें, क्योंकि SSE / SSE2 में कोई अतिरिक्त परिशुद्धता नहीं है। doubleऔर floatXMM रजिस्टरों में var वास्तव में IEEE 64-बिट या 32-बिट प्रारूप में हैं। (X87 के विपरीत, जहां रजिस्टर हमेशा 80-बिट होते हैं, और मेमोरी राउंड को 32 या 64 बिट तक संग्रहीत करते हैं।)
पीटर कॉर्डेस

3

स्वीकृत उत्तर सही है यदि आप एक x86 लक्ष्य को संकलित कर रहे हैं जिसमें SSE2 शामिल नहीं है। सभी आधुनिक x86 प्रोसेसर SSE2 का समर्थन करते हैं, इसलिए यदि आप इसका लाभ उठा सकते हैं, तो आपको चाहिए:

-mfpmath=sse -msse2 -ffp-contract=off

चलिए इसे तोड़ते हैं।

-mfpmath=sse -msse2। यह SSE2 रजिस्टरों का उपयोग करके राउंडिंग करता है, जो मेमोरी के लिए प्रत्येक मध्यवर्ती परिणाम को संग्रहीत करने की तुलना में बहुत तेज है। ध्यान दें कि यह x86-64 के लिए GCC पर पहले से ही डिफ़ॉल्ट है । से जीसीसी विकि :

SSE2 का समर्थन करने वाले अधिक आधुनिक x86 प्रोसेसर पर, कंपाइलर विकल्पों को निर्दिष्ट करने से -mfpmath=sse -msse2सभी फ्लोट सुनिश्चित होते हैं और एसएसई रजिस्टरों में डबल ऑपरेशन किए जाते हैं और सही ढंग से गोल होते हैं। ये विकल्प ABI को प्रभावित नहीं करते हैं और इसलिए जब भी संभव हो संख्यात्मक रूप से अनुमानित परिणामों के लिए इसका उपयोग किया जाना चाहिए।

-ffp-contract=off। हालाँकि, एक सटीक मिलान के लिए गोलाई नियंत्रित करना पर्याप्त नहीं है। FMA (जुड़े हुए बहु-जोड़) निर्देश गोलाई व्यवहार को उसके गैर-फ़्यूज़ किए गए समकक्षों के रूप में बदल सकते हैं, इसलिए हमें इसे अक्षम करने की आवश्यकता है। यह GCC का नहीं, बल्कि Clang का डिफ़ॉल्ट है। जैसा कि इस उत्तर द्वारा समझाया गया है :

एक FMA में केवल एक राउंडिंग होती है (यह आंतरिक अस्थायी गुणा परिणाम के लिए प्रभावी रूप से अनंत सटीकता रखता है), जबकि एक ADD + MUL दो है।

एफएमए को अक्षम करने से, हमें कुछ प्रदर्शन (और सटीकता) की कीमत पर, डिबग और रिलीज पर मेल खाने वाले परिणाम मिलते हैं। हम अभी भी SSE और AVX के अन्य प्रदर्शन लाभों का लाभ उठा सकते हैं।


1

मैंने इस समस्या में और खुदाई की और मैं और अधिक प्राथमिकताएँ ला सकता हूं। सबसे पहले, x84_64 पर gcc के अनुसार ४.४५ और ४.५५ के सटीक निरूपण निम्नलिखित हैं (अंतिम सटीकता को मुद्रित करने के लिए libquadmath के साथ):

float 32:   4.44999980926513671875
double 64:  4.45000000000000017763568394002504646778106689453125
doublex 80: 4.449999999999999999826527652402319290558807551860809326171875
quad 128:   4.45000000000000000000000000000000015407439555097886824447823540679418548304813185723105561919510364532470703125

float 32:   4.55000019073486328125
double 64:  4.54999999999999982236431605997495353221893310546875
doublex 80: 4.550000000000000000173472347597680709441192448139190673828125
quad 128:   4.54999999999999999999999999999999984592560444902113175552176459320581451695186814276894438080489635467529296875

जैसा कि मैक्सिम ने कहा, यह समस्या एफपीयू रजिस्टरों के 80 बिट्स आकार के कारण है।

लेकिन विंडोज पर कभी समस्या क्यों नहीं आ रही है? IA-32 पर, x87 FPU को 53 बिट्स के मंटिसा (64 बिट्स के कुल आकार के बराबर) के लिए एक आंतरिक परिशुद्धता का उपयोग करने के लिए कॉन्फ़िगर किया गया था double। लिनक्स और मैक ओएस के लिए, 64 बिट्स की डिफ़ॉल्ट परिशुद्धता का उपयोग किया गया था (80 बिट्स के कुल आकार के बराबर long double):। तो इन विभिन्न प्लेटफार्मों पर FPU के नियंत्रण शब्द को बदलकर (निर्देशों के अनुक्रम बग को ट्रिगर किया जाएगा) यह समस्या संभव है या नहीं। समस्या बग 323 के रूप में सामने आने की सूचना दी गई थी (कम से कम टिप्पणी 92 पढ़ें!)।

विंडोज पर मंटिसा सटीक दिखाने के लिए, आप इसे वीसी ++ के साथ 32 बिट्स में संकलित कर सकते हैं:

#include "stdafx.h"
#include <stdio.h>  
#include <float.h>  

int main(void)
{
    char t[] = { 64, 53, 24, -1 };
    unsigned int cw = _control87(0, 0);
    printf("mantissa is %d bits\n", t[(cw >> 16) & 3]);
}

और Linux / Cygwin पर:

#include <stdio.h>

int main(int argc, char **argv)
{
    char t[] = { 24, -1, 53, 64 };
    unsigned int cw = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (*&cw));
    printf("mantissa is %d bits\n", t[(cw >> 8) & 3]);
}

ध्यान दें कि gcc के साथ आप FPU परिशुद्धता को सेट कर सकते हैं -mpc32/64/80, हालाँकि इसे Cygwin में अनदेखा किया गया है। लेकिन ध्यान रखें कि यह मंटिसा के आकार को संशोधित करेगा, लेकिन घातांक एक नहीं, अन्य प्रकार के विभिन्न व्यवहार के लिए दरवाजा खुला रहने देगा।

X86_64 आर्किटेक्चर पर, SSE का उपयोग tmandry द्वारा कहा गया है , इसलिए समस्या तब तक नहीं होगी जब तक कि आप पुराने x87 FPU को FP कंप्यूटिंग के लिए बाध्य नहीं करते हैं -mfpmath=387, या जब तक आप 32 बिट्स मोड के साथ संकलन नहीं करते हैं -m32(आपको मल्टीबिल पैकेज की आवश्यकता होगी)। मैं झंडे के विभिन्न संयोजनों और gcc के संस्करणों के साथ लिनक्स पर समस्या को पुन: उत्पन्न कर सकता हूं:

g++-5 -m32 floating.cpp -O1
g++-8 -mfpmath=387 floating.cpp -O1

मैंने VC + / gcc / tcc के साथ Windows या Cygwin पर कुछ संयोजनों की कोशिश की, लेकिन बग कभी नहीं दिखा। मुझे लगता है कि उत्पन्न निर्देश का क्रम समान नहीं है।

अंत में, ध्यान दें कि 4.45 या 4.55 के साथ इस समस्या को रोकने के लिए एक विदेशी तरीका उपयोग करना होगा _Decimal32/64/128, लेकिन समर्थन वास्तव में दुर्लभ है ... मैंने अभी बहुत समय बिताया है, जिसके साथ प्रिंट करने में सक्षम हो libdfp!


0

व्यक्तिगत रूप से, मैंने एक ही समस्या को दूसरे तरीके से मारा है - जीसीसी से वी.एस. ज्यादातर उदाहरणों में मुझे लगता है कि अनुकूलन से बचना बेहतर है। यह केवल तभी सार्थक है जब आप संख्यात्मक तरीकों के साथ काम कर रहे हों जिसमें फ्लोटिंग पॉइंट डेटा की बड़ी सरणियाँ शामिल हों। यहां तक ​​कि disassembling के बाद भी मैं अक्सर compilers विकल्पों से अभिभूत हूं। बहुत बार कम्पाइलर इंट्रिंसिक्स का उपयोग करना आसान होता है या केवल असेंबली स्वयं लिखें।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.