सवाल जीसीसी एक * ए * ए * ए * ए * ए (ए * ए * ए) * (ए * ए * ए) को अनुकूलित क्यों नहीं करता है?


मैं एक वैज्ञानिक अनुप्रयोग पर कुछ संख्यात्मक अनुकूलन कर रहा हूं। एक बात मैंने देखी है कि जीसीसी कॉल को अनुकूलित करेगा pow(a,2) इसे संकलित करके a*a, लेकिन कॉल pow(a,6) अनुकूलित नहीं है और वास्तव में लाइब्रेरी फ़ंक्शन को कॉल करेगा pow, जो प्रदर्शन को धीमा कर देता है। (इसके विपरीत, इंटेल सी ++ कंपाइलरनिष्पादन योग्य icc, पुस्तकालय कॉल को खत्म कर देगा pow(a,6)।)

मैं इस बारे में उत्सुक हूं कि जब मैंने प्रतिस्थापित किया pow(a,6) साथ में a*a*a*a*a*a जीसीसी 4.5.1 और विकल्पों का उपयोग करना "-O3 -lm -funroll-loops -msse4", यह 5 का उपयोग करता है mulsd निर्देश:

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13

जबकि मैं लिखता हूं (a*a*a)*(a*a*a), यह उत्पादन करेगा

movapd  %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm14, %xmm13
mulsd   %xmm13, %xmm13

जो गुणा निर्देशों की संख्या को 3 तक कम कर देता है। icc समान व्यवहार है।

संकलक इस अनुकूलन चाल को क्यों पहचानते हैं?


1965
2018-06-21 18:49


मूल


"पाओ (ए, 6)" को पहचानने का क्या अर्थ है? - Varun Madiath
उम ... आप जानते हैं कि एएएएएए और (एएएक) * (एकए * ए) फ्लोटिंग पॉइंट नंबरों के साथ समान नहीं हैं, है ना? आपको -फनसेफ-गणित या -फैस्ट-गणित या उसके लिए कुछ उपयोग करना होगा। - Damon
मेरा सुझाव है कि आप डेविड गोल्डबर्ग द्वारा "फ्लोटिंग पॉइंट अंकगणित के बारे में क्या हर कंप्यूटर वैज्ञानिक को जानना चाहिए" पढ़ना है: download.oracle.com/docs/cd/E19957-01/806-3568/... जिसके बाद आपको उस टैर गड्ढे की पूरी तरह समझ हो जाएगी जिसे आपने अभी चलाया है! - Phil Armstrong
एक बिल्कुल उचित सवाल है। 20 साल पहले मैंने एक ही सामान्य प्रश्न पूछा, और उस एकल बाधा को कुचलने से, मोंटे कार्लो सिमुलेशन के निष्पादन समय को 21 घंटे से 7 घंटे तक कम कर दिया गया। आंतरिक लूप में कोड को प्रक्रिया में 13 ट्रिलियन बार निष्पादित किया गया था, लेकिन इसे ओवर-नाइट विंडो में सिमुलेशन मिला। (नीचे जवाब देखें)
शायद फेंक दो (a*a)*(a*a)*(a*a) मिश्रण में भी। गुणा की समान संख्या, लेकिन शायद अधिक सटीक। - Rok Kralj


जवाब:


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

नतीजतन, अधिकांश कंपाइलर फ़्लोटिंग पॉइंट गणनाओं को पुन: व्यवस्थित करने के बारे में बहुत रूढ़िवादी हैं, जब तक कि वे सुनिश्चित न हों कि उत्तर वही रहेगा, या जब तक कि आप उन्हें न बताएं कि आपको संख्यात्मक सटीकता की परवाह नहीं है। उदाहरण के लिए: -fassociative-math विकल्प जीसीसी का जो जीसीसी को फ्लोटिंग प्वाइंट ऑपरेशंस को फिर से स्थापित करने की अनुमति देता है, या यहां तक ​​कि -ffast-math विकल्प जो गति के खिलाफ सटीकता के और भी आक्रामक ट्रेडऑफ की अनुमति देता है।


2567
2018-06-22 15:32



हाँ। -फैस्ट-गणित के साथ यह अनुकूलन कर रहा है। अच्छा विचार! लेकिन चूंकि हमारा कोड गति से अधिक सटीकता से संबंधित है, इसलिए यह बेहतर नहीं हो सकता है कि इसे पास न किया जाए। - xis
आईआईआरसी सी 99 संकलक को ऐसे "असुरक्षित" एफपी अनुकूलन करने की अनुमति देता है, लेकिन जीसीसी (x87 के अलावा किसी भी अन्य चीज़ पर) आईईईई 754 का पालन करने का उचित प्रयास करता है - यह "त्रुटि सीमा" नहीं है; केवल एक सही जवाब है। - tc.
कार्यान्वयन विवरण pow न तो यहां और न ही वहां हैं; यह उत्तर भी संदर्भ नहीं देता है pow। - Stephen Canon
@nedR: आईसीसी ने फिर से सहयोग की अनुमति देने के लिए चूक की। यदि आप मानक-अनुरूप व्यवहार प्राप्त करना चाहते हैं, तो आपको सेट करने की आवश्यकता है -fp-model precise आईसीसी के साथ clang तथा gcc सख्त अनुरूपता w.r.t. के लिए डिफ़ॉल्ट reassociation। - Stephen Canon
@ xis, यह वास्तव में ऐसा नहीं है -fassociative-mathगलत होगा; ये बस यही है a*a*a*a*a*a तथा (a*a*a)*(a*a*a) अलग है। यह सटीकता के बारे में नहीं है; यह मानक अनुरूपता और कड़ाई से दोहराने योग्य परिणामों के बारे में है, उदा। किसी भी संकलक पर एक ही परिणाम। फ़्लोटिंग पॉइंट नंबर पहले से सटीक नहीं हैं। यह संकलन करने के लिए शायद ही कभी अनुचित है -fassociative-math। - Paul Draper


Lambdageek सही ढंग से इंगित करता है कि क्योंकि सहयोगीता फ्लोटिंग-पॉइंट संख्याओं के लिए नहीं है, "अनुकूलन" a*a*a*a*a*a सेवा मेरे (a*a*a)*(a*a*a) मूल्य बदल सकता है। यही कारण है कि इसे सी 99 द्वारा अस्वीकृत नहीं किया जाता है (जब तक कि उपयोगकर्ता द्वारा विशेष रूप से संकलक ध्वज या प्रगमा के माध्यम से अनुमति नहीं दी जाती)। आम तौर पर, धारणा यह है कि प्रोग्रामर ने लिखा कि उसने किसी कारण से क्या किया है, और संकलक को इसका सम्मान करना चाहिए। अगर तुम चाहते हो (a*a*a)*(a*a*a), लिखो।

यह लिखने के लिए दर्द हो सकता है, यद्यपि; जब आप उपयोग करते हैं तो कंपाइलर केवल सही चीज़ [जिसे आप मानते हैं] क्यों नहीं कर सकते हैं pow(a,6)? क्योंकि यह होगा गलत करने के लिए। एक अच्छी गणित पुस्तकालय के साथ एक मंच पर, pow(a,6) या तो से काफी सटीक है a*a*a*a*a*a या (a*a*a)*(a*a*a)। बस कुछ डेटा प्रदान करने के लिए, मैंने अपने मैक प्रो पर एक छोटा सा प्रयोग चलाया, जिसमें [1) के बीच सभी एकल-परिशुद्धता फ़्लोटिंग संख्याओं के लिए ^ 6 का मूल्यांकन करने में सबसे खराब त्रुटि को मापना:

worst relative error using    powf(a, 6.f): 5.96e-08
worst relative error using (a*a*a)*(a*a*a): 2.94e-07
worst relative error using     a*a*a*a*a*a: 2.58e-07

का उपयोग करते हुए pow एक गुणा पेड़ के बजाय त्रुटि से एक त्रुटि को कम कर देता है 4 का कारक। कंपाइलर्स को "ऑप्टिमाइज़ेशन" नहीं करना चाहिए (और आमतौर पर नहीं) जो त्रुटि को बढ़ाता है जब तक कि उपयोगकर्ता द्वारा ऐसा करने के लिए लाइसेंस प्राप्त न हो (उदा। -ffast-math)।

ध्यान दें कि जीसीसी प्रदान करता है __builtin_powi(x,n) एक विकल्प के रूप में pow( ), जो एक इनलाइन गुणा पेड़ उत्पन्न करना चाहिए। इसका उपयोग करें यदि आप प्रदर्शन के लिए सटीकता से व्यापार करना चाहते हैं, लेकिन तेजी से गणित को सक्षम नहीं करना चाहते हैं।


614
2018-06-22 22:39



ध्यान दें कि विजुअल सी ++ पाउ () के 'वर्धित' संस्करण प्रदान करता है। फोन करके _set_SSE2_enable(<flag>) साथ में flag=1, यदि संभव हो तो यह एसएसई 2 का उपयोग करेगा। इससे थोड़ा सा सटीकता कम हो जाती है, लेकिन गति में सुधार होता है (कुछ मामलों में)। MSDN: _set_SSE2_enable () तथा पॉव () - TkTech
@ टीकेटेक: किसी भी कम सटीकता माइक्रोसॉफ्ट के कार्यान्वयन के कारण है, न कि इस्तेमाल किए गए रजिस्टरों का आकार। एक वितरित करना संभव है सही ढंग से गोल  pow पुस्तकालय लेखक इतने प्रेरित हैं, केवल 32-बिट रजिस्टरों का उपयोग करते हुए। एसएसई आधारित हैं pow कार्यान्वयन जो हैं अधिक अधिकांश x87- आधारित कार्यान्वयन से सटीक, और ऐसे कार्यान्वयन भी हैं जो गति के लिए कुछ सटीकता से व्यापार करते हैं। - Stephen Canon
@ टीकेटेक: बेशक, मैं सिर्फ यह स्पष्ट करना चाहता था कि सटीकता में कमी लाइब्रेरी लेखकों द्वारा किए गए विकल्पों के कारण है, एसएसई के उपयोग के लिए आंतरिक नहीं। - Stephen Canon
मुझे यह जानने में दिलचस्पी है कि आपने सापेक्ष त्रुटियों की गणना के लिए "स्वर्ण मानक" के रूप में क्या उपयोग किया - मुझे आमतौर पर यह उम्मीद होगी कि यह होगा a*a*a*a*a*a, लेकिन जाहिर है कि मामला नहीं है! :) - j_random_hacker
@j_random_hacker: चूंकि मैं एकल परिशुद्धता परिणामों की तुलना कर रहा था, सोने के मानक के लिए डबल-परिशुद्धता पर्याप्त - एक त्रुटिएएएएडबल में गणना एक * है एकल-परिशुद्धता गणनाओं में से किसी की त्रुटि से छोटा। - Stephen Canon


एक और समान मामला: अधिकांश कंपाइलर अनुकूलित नहीं होंगे a + b + c + d सेवा मेरे (a + b) + (c + d) (यह एक अनुकूलन है क्योंकि दूसरी अभिव्यक्ति को बेहतर ढंग से पाइपलाइन किया जा सकता है) और इसे मूल्यांकन के रूप में मूल्यांकन करें (यानी (((a + b) + c) + d))। यह भी कोने के मामलों के कारण है:

float a = 1e35, b = 1e-5, c = -1e35, d = 1e-5;
printf("%e %e\n", a + b + c + d, (a + b) + (c + d));

यह आउटपुट 1.000000e-05 0.000000e+00


152
2018-06-23 11:44



यह बिल्कुल वही नहीं है। गुणा / विभाजन (0 से विभाजन को छोड़कर) के क्रम को बदलना योग / समाप्ति के परिवर्तनीय क्रम से सुरक्षित है। मेरी विनम्र राय में, कंपाइलर को mults./divs को जोड़ने का प्रयास करना चाहिए। क्योंकि ऐसा करने से संचालन की कुल संख्या कम हो जाती है और प्रदर्शन लाभ के बगल में भी एक सटीक लाभ होता है। - GameDeveloper
@DarioOO: यह कोई सुरक्षित नहीं है। गुणा करें और विभाजित एक्सपोनेंट के अतिरिक्त और घटाव के समान हैं, और ऑर्डर बदलने से अस्थायी रूप से एक्सपोनेंट की संभावित सीमा से अधिक हो सकते हैं। (बिल्कुल वही नहीं, क्योंकि एक्सपोनेंट को परिशुद्धता का नुकसान नहीं होता है ... लेकिन प्रतिनिधित्व अभी भी काफी सीमित है, और पुनर्वितरण अप्रत्याशित मूल्यों का कारण बन सकता है) - Ben Voigt
मुझे लगता है कि आप कुछ कैलकुस पृष्ठभूमि खो रहे हैं। 2 संख्याओं को मल्टीप्लिंग और विभाजित करने से त्रुटि की एक ही राशि लागू होती है। जबकि घटाना / जोड़ना 2 संख्याएं एक बड़ी त्रुटि पेश कर सकती हैं, खासकर जब 2 संख्याएं परिमाण के क्रम अलग होती हैं, इसलिए यह उप / जोड़ से सुरक्षित पुनः-व्यवस्था माल / विभाजन है क्योंकि यह अंतिम त्रुटि में मामूली परिवर्तन पेश करती है। - GameDeveloper
@DarioOO: जोखिम mul / div के साथ अलग है: पुनरावृत्ति या तो अंतिम परिणाम में एक नगण्य परिवर्तन, या किसी बिंदु पर एक्सपोनेंट ओवरफ्लो बनाता है (जहां यह पहले नहीं होगा) और नतीजा काफी अलग है (संभावित रूप से + inf या 0)। - Peter Cordes


फोरट्रान (वैज्ञानिक कंप्यूटिंग के लिए डिज़ाइन किया गया) में एक अंतर्निहित पावर ऑपरेटर है, और जहां तक ​​मुझे पता है कि फोरट्रान कंपाइलर्स आमतौर पर आपके द्वारा वर्णित एक समान रूप में पूर्णांक शक्तियों को बढ़ाने का अनुकूलन करेंगे। दुर्भाग्य से सी / सी ++ में पावर ऑपरेटर नहीं है, केवल लाइब्रेरी फ़ंक्शन है pow()। यह स्मार्ट कंपेलरों को इलाज से रोका नहीं है pow विशेष रूप से और विशेष मामलों के लिए इसे तेजी से कंप्यूटिंग करते हुए, लेकिन ऐसा लगता है कि वे इसे कम सामान्य रूप से करते हैं ...

कुछ साल पहले मैं एक इष्टतम तरीके से पूर्णांक शक्तियों की गणना करने के लिए और अधिक सुविधाजनक बनाने की कोशिश कर रहा था, और निम्नलिखित के साथ आया था। यह सी ++ है, हालांकि सी नहीं है, और अभी भी संकलक पर निर्भर करता है कि चीजों को अनुकूलित / इनलाइन करने के तरीके के बारे में कुछ हद तक स्मार्ट है। वैसे भी, आशा है कि आप इसे अभ्यास में उपयोगी पा सकते हैं:

template<unsigned N> struct power_impl;

template<unsigned N> struct power_impl {
    template<typename T>
    static T calc(const T &x) {
        if (N%2 == 0)
            return power_impl<N/2>::calc(x*x);
        else if (N%3 == 0)
            return power_impl<N/3>::calc(x*x*x);
        return power_impl<N-1>::calc(x)*x;
    }
};

template<> struct power_impl<0> {
    template<typename T>
    static T calc(const T &) { return 1; }
};

template<unsigned N, typename T>
inline T power(const T &x) {
    return power_impl<N>::calc(x);
}

जिज्ञासा के लिए स्पष्टीकरण: यह शक्तियों की गणना करने का सबसे अच्छा तरीका नहीं है, लेकिन तब से इष्टतम समाधान ढूंढना एक एनपी-पूर्ण समस्या है और यह केवल छोटी शक्तियों के लिए करने योग्य है (जैसा कि उपयोग करने के विपरीत है pow), विस्तार से झगड़ा करने का कोई कारण नहीं है।

फिर बस इसका इस्तेमाल करें power<6>(a)

यह शक्तियों को टाइप करना आसान बनाता है (6 को वर्तनी करने की आवश्यकता नहीं है aमाता पिता के साथ), और आपको इस तरह के अनुकूलन के बिना अनुमति देता है -ffast-math यदि आपके पास कुछ परिशुद्धता निर्भर है जैसे कि मुआवजा सारांश (एक उदाहरण जहां संचालन का आदेश आवश्यक है)।

आप शायद यह भी भूल सकते हैं कि यह सी ++ है और इसे सी प्रोग्राम में उपयोग करें (यदि यह एक सी ++ कंपाइलर के साथ संकलित करता है)।

उम्मीद है कि यह उपयोगी हो सकता है।

संपादित करें:

यह मेरे संकलक से मिलता है:

के लिये a*a*a*a*a*a,

    movapd  %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm1, %xmm0

के लिये (a*a*a)*(a*a*a),

    movapd  %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm1, %xmm0
    mulsd   %xmm0, %xmm0

के लिये power<6>(a),

    mulsd   %xmm0, %xmm0
    movapd  %xmm0, %xmm1
    mulsd   %xmm0, %xmm1
    mulsd   %xmm0, %xmm1

74
2018-06-23 10:07



इष्टतम पावर पेड़ ढूंढना मुश्किल हो सकता है, लेकिन चूंकि यह केवल छोटी शक्तियों के लिए दिलचस्प है, इसलिए स्पष्ट उत्तर यह है कि एक बार इसे पहले से प्रीकंप्यूट करें (Knuth 100 तक एक टेबल प्रदान करता है) और उस हार्डकोडेड टेबल का उपयोग करें (यही वह है जो जीसीसी आंतरिक रूप से पाउ के लिए करता है) । - Marc Glisse
आधुनिक प्रोसेसर पर, गति विलंबता तक सीमित है। उदाहरण के लिए, गुणा का परिणाम पांच चक्रों के बाद उपलब्ध हो सकता है। उस स्थिति में, कुछ शक्ति बनाने का सबसे तेज़ तरीका ढूंढना अधिक कठिन हो सकता है। - gnasher729
आप पावर पेड़ को खोजने का भी प्रयास कर सकते हैं जो रिश्तेदार गोल त्रुटि के लिए सबसे ऊपरी ऊपरी बाउंड देता है, या सबसे कम औसत रिश्तेदार गोल त्रुटि। - gnasher729
बूस्ट ने इसके लिए भी समर्थन किया है, उदाहरण के लिए को बढ़ावा देने :: गणित :: पॉव <6> (एन); मुझे लगता है कि यह सामान्य कारकों को निकालने से गुणाओं की संख्या को कम करने की भी कोशिश करता है। - gast128
अछा सुझाव ! मैंने पहले से ही फैक्टरियल प्रीकंप्यूटिंग के लिए ऐसा किया है। - Caduchon


क्योंकि 32-बिट फ़्लोटिंग-पॉइंट नंबर - जैसे कि 1.024 - 1.024 नहीं है। कंप्यूटर में, 1.024 एक अंतराल है: (1.024-ई) से (1.024 + ई), जहां "ई" एक त्रुटि का प्रतिनिधित्व करता है। कुछ लोग इसका एहसास करने में विफल रहते हैं और यह भी मानते हैं कि * एक * में उन संख्याओं से जुड़ी त्रुटियों के बिना मनमानी-परिशुद्धता संख्याओं के गुणा के लिए खड़ा है। कुछ लोगों को इसका एहसास करने में असफल होने का कारण शायद गणित की गणना प्राथमिक विद्यालयों में होती है: बिना किसी त्रुटि के आदर्श संख्याओं के साथ काम करना, और यह मानना ​​कि गुणा करने के दौरान "ई" को अनदेखा करना ठीक है। उन्हें "फ्लोट ए = 1.2", "ए * ए * ए" और इसी तरह के सी कोड में "ई" निहित दिखाई नहीं देता है।

क्या अधिकांश प्रोग्रामर इस विचार को पहचान सकते हैं (और निष्पादित करने में सक्षम हैं) कि सी अभिव्यक्ति ए * ए * ए * ए * ए * वास्तव में आदर्श संख्याओं के साथ काम नहीं कर रही है, तो जीसीसी कंपाइलर "ए * ए को अनुकूलित करने के लिए स्वतंत्र होगा * ए * ए * ए * ए "कहने में" टी = (ए * ए); टी * टी * टी "जिसके लिए गुणा की एक छोटी संख्या की आवश्यकता होती है। लेकिन दुर्भाग्यवश, जीसीसी कंपाइलर को यह नहीं पता कि कोडर लिखने वाला प्रोग्रामर सोचता है कि "ए" एक त्रुटि है या बिना किसी त्रुटि के। और इसलिए जीसीसी केवल वही करेगा जो स्रोत कोड जैसा दिखता है - क्योंकि जीसीसी अपनी "नग्न आंख" के साथ देखता है।

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


49
2018-03-29 06:51



फ़्लोटिंग पॉइंट नंबर सटीक हैं। वे बिल्कुल जरूरी नहीं हैं जो आपने अपेक्षित थे। इसके अलावा, ईपीएसलॉन के साथ तकनीक वास्तविकता में चीजों से निपटने के लिए एक अनुमान है, क्योंकि वास्तविक अपेक्षित त्रुटि मंटिसा के पैमाने के सापेक्ष है, यानी, आप आमतौर पर लगभग 1 एलएसबी तक पहुंच जाते हैं, लेकिन इससे बढ़ सकता है यदि आप सावधान नहीं हैं तो प्रत्येक ऑपरेशन किया जाता है इसलिए फ्लोटिंग पॉइंट के साथ गैर-तुच्छ कुछ भी करने से पहले एक संख्यात्मक विश्लेषक से परामर्श लें। यदि आप संभवतः कर सकते हैं तो एक उचित पुस्तकालय का प्रयोग करें। - Donal Fellows
@DonalFellows: आईईईई मानक के लिए आवश्यक है कि फ़्लोटिंग-पॉइंट गणनाएं परिणाम उत्पन्न करें जो परिणाम सटीक रूप से मेल खाती है कि परिणाम क्या होगा यदि स्रोत ऑपरेटरों सटीक मान थे, लेकिन इसका मतलब यह नहीं है कि वे वास्तव में का प्रतिनिधित्व सटीक मूल्य यह कई मामलों में 0.1f को (1,677,722 +/- 0.5) / 16,777,216 के रूप में मानने के लिए अधिक उपयोगी है, जिसे सटीक मात्रा के रूप में मानने के लिए उस अनिश्चितता से निहित दशमलव अंकों की संख्या के साथ प्रदर्शित किया जाना चाहिए (1,677,722 +/- 0.5) / 16,777,216 (जो 24 दशमलव अंकों पर प्रदर्शित किया जाना चाहिए)। - supercat
@supercat: आईईईई -754 उस बिंदु पर स्पष्ट है कि फ़्लोटिंग-पॉइंट डेटा कर सटीक मूल्यों का प्रतिनिधित्व करें; खंड 3.2 - 3.4 प्रासंगिक खंड हैं। आप, निश्चित रूप से, उन्हें अन्यथा व्याख्या करना चुन सकते हैं, जैसे आप व्याख्या करना चुन सकते हैं int x = 3 इसका मतलब है कि x 3 +/- 0.5 है। - Stephen Canon
@supercat: मैं पूरी तरह से सहमत हूं, लेकिन इसका मतलब यह नहीं है Distance इसके संख्यात्मक मूल्य के बराबर नहीं है; इसका मतलब है कि संख्यात्मक मूल्य केवल कुछ भौतिक मात्रा के मॉडलिंग के लिए एक अनुमान है। - Stephen Canon
संख्यात्मक विश्लेषण के लिए, यदि आप फ़्लोटिंग पॉइंट नंबरों को अंतराल के रूप में नहीं समझते हैं, तो आपके मस्तिष्क आपको धन्यवाद देंगे, लेकिन सटीक मानों के रूप में (जो वास्तव में आपके इच्छित मूल्य नहीं होते हैं)। उदाहरण के लिए, यदि एक्स 0.1 से कम त्रुटि के साथ कहीं 4.5 है, और आप गणना करते हैं (x + 1) - x, "अंतराल" व्याख्या आपको 0.8 से 1.2 तक अंतराल के साथ छोड़ देती है, जबकि "सटीक मान" व्याख्या बताती है आप परिणाम डबल 2 परिशुद्धता में अधिकतम 2 ^ (- 50) की त्रुटि के साथ 1 होगा। - gnasher729


जीसीसी वास्तव में एक * ए * ए * ए * ए * ए (ए * ए * ए) * (ए * ए * ए) अनुकूलित करता है जब एक पूर्णांक होता है। मैंने इस आदेश के साथ प्रयास किया:

$ echo 'int f(int x) { return x*x*x*x*x*x; }' | gcc -o - -O2 -S -masm=intel -x c -

बहुत सारे जीसीसी झंडे हैं लेकिन कुछ भी कल्पना नहीं है। उनका मतलब है: stdin से पढ़ें; ओ 2 अनुकूलन स्तर का उपयोग करें; बाइनरी के बजाय आउटपुट असेंबली भाषा लिस्टिंग; लिस्टिंग इंटेल असेंबली भाषा वाक्यविन्यास का उपयोग करना चाहिए; इनपुट सी भाषा में है (आमतौर पर भाषा इनपुट फ़ाइल एक्सटेंशन से अनुमानित है, लेकिन stdin से पढ़ने पर कोई फ़ाइल एक्सटेंशन नहीं है); और stdout लिखो।

आउटपुट का महत्वपूर्ण हिस्सा यहां दिया गया है। मैंने कुछ टिप्पणियों के साथ टिप्पणी की है जो बताती है कि असेंबली भाषा में क्या हो रहा है:

    ; x is in edi to begin with.  eax will be used as a temporary register.
    mov    eax, edi     ; temp1 = x
    imul    eax, edi    ; temp2 = x * temp1
    imul    eax, edi    ; temp3 = x * temp2
    imul    eax, eax    ; temp4 = temp3 * temp3

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

$ gcc --version
gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1

जैसा कि अन्य पोस्टर्स ने नोट किया है, फ्लोटिंग पॉइंट में यह विकल्प संभव नहीं है, क्योंकि फ्लोटिंग पॉइंट अंकगणित वास्तव में सहयोगी नहीं है।


49
2018-06-27 21:03



यह पूर्णांक गुणा के लिए कानूनी है क्योंकि दो का पूरक ओवरफ्लो अपरिभाषित व्यवहार है। यदि ओवरफ्लो होने वाला है, तो यह कहीं भी होगा, भले ही संचालन के बावजूद। इसलिए, कोई ओवरफ्लो वाला अभिव्यक्ति इसका मूल्यांकन नहीं करता है, अभिव्यक्तियां कि ओवरफ़्लो अपरिभाषित व्यवहार हैं, इसलिए संकलक उस बिंदु को बदलने के लिए ठीक है जिस पर अतिप्रवाह होता है। जीसीसी इसके साथ करता है unsigned intभी - Peter Cordes


कोई पोस्टर ने अभी तक फ्लोटिंग एक्सप्रेशन के संकुचन का उल्लेख नहीं किया है (आईएसओ सी मानक, 6.5 पी 8 और 7.12.2)। अगर FP_CONTRACT प्रगति पर सेट है ON, कंपाइलर को अभिव्यक्ति का सम्मान करने की अनुमति है जैसे कि a*a*a*a*a*a एक ही ऑपरेशन के रूप में, जैसे कि एक गोल के साथ बिल्कुल मूल्यांकन किया जाता है। उदाहरण के लिए, एक कंपाइलर इसे एक आंतरिक पावर फ़ंक्शन द्वारा प्रतिस्थापित कर सकता है जो तेज़ और अधिक सटीक दोनों है। यह विशेष रूप से दिलचस्प है क्योंकि व्यवहार को प्रोग्रामर द्वारा आंशिक रूप से स्रोत कोड में नियंत्रित किया जाता है, जबकि अंतिम उपयोगकर्ता द्वारा प्रदान किए गए कंपाइलर विकल्प कभी-कभी गलत तरीके से उपयोग किए जा सकते हैं।

की डिफ़ॉल्ट स्थिति FP_CONTRACT प्रगमा कार्यान्वयन-परिभाषित है, ताकि एक कंपाइलर को डिफ़ॉल्ट रूप से ऐसे अनुकूलन करने की अनुमति दी जा सके। इस प्रकार पोर्टेबल कोड जिसे आईईईई 754 नियमों का सख्ती से पालन करने की आवश्यकता है, इसे स्पष्ट रूप से सेट करना चाहिए OFF

यदि कोई कंपाइलर इस प्रज्ञा का समर्थन नहीं करता है, तो डेवलपर ने इसे सेट करने के लिए चुना है, तो इस तरह के किसी भी अनुकूलन से बचकर रूढ़िवादी होना चाहिए OFF

जीसीसी इस प्राग का समर्थन नहीं करता है, लेकिन डिफ़ॉल्ट विकल्पों के साथ, यह मानता है ON; इस प्रकार हार्डवेयर एफएमए के साथ लक्ष्य के लिए, यदि कोई परिवर्तन को रोकना चाहता है a*b+c एफएमए (ए, बी, सी) के लिए, किसी को एक विकल्प प्रदान करने की आवश्यकता है -ffp-contract=off (स्पष्ट रूप से प्रज्ञा को सेट करने के लिए OFF) या -std=c99 (कुछ सी मानक संस्करण के अनुरूप जीसीसी को बताने के लिए, यहां सी 99, इस प्रकार उपर्युक्त पैराग्राफ का पालन करें)। अतीत में, बाद का विकल्प परिवर्तन को रोक नहीं रहा था, जिसका अर्थ है कि जीसीसी इस बिंदु पर अनुरूप नहीं था: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=37845


27
2018-06-23 12:44



लंबे समय से लोकप्रिय प्रश्न कभी-कभी अपनी उम्र दिखाते हैं। 2011 में इस सवाल से पूछा और उत्तर दिया गया था, जब जीसीसी को हाल ही में सी 99 मानक के सम्मान के लिए क्षमा नहीं किया जा सकता था। बेशक अब यह 2014 है, इसलिए जीसीसी ... अहम। - Pascal Cuoq
क्या आप तुलनात्मक रूप से हाल ही में फ़्लोटिंग-पॉइंट सवालों के जवाब देने के बजाय उत्तरदायी उत्तर के जवाब नहीं दे रहे हैं? खांसी stackoverflow.com/questions/23703408 खांसी - Pascal Cuoq
मुझे लगता है कि परेशान है कि जीसीसी सी 99 फ्लोटिंग पॉइंट प्रोग्राम्स को लागू नहीं करता है। - David Monniaux


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


26
2018-06-21 18:52



फ़्लोटिंग पॉइंट हमेशा निर्धारक है। - Alice
@ एलिस यह स्पष्ट रूप से स्पष्ट रूप से स्पष्ट लगता है कि यहां बोजर्न कोड के अर्थ में 'निर्धारक' का उपयोग कर रहा है, जो विभिन्न प्लेटफार्मों और विभिन्न कंपाइलर संस्करणों आदि (बाहरी चर जो प्रोग्रामर के नियंत्रण से बाहर हो सकता है) पर समान परिणाम दे रहा है - कमी के विपरीत रन टाइम पर वास्तविक संख्यात्मक यादृच्छिकता का। यदि आप यह इंगित कर रहे हैं कि यह शब्द का उचित उपयोग नहीं है, तो मैं इसके साथ बहस नहीं कर रहा हूं। - greggo
@greggo जो भी कहता है उसकी व्याख्या में भी, यह अभी भी गलत है; आईईईई 754 का यह पूरा बिंदु है, प्लेटफार्मों में अधिकांश (यदि नहीं सभी) संचालन के लिए समान विशेषताओं को प्रदान करने के लिए। अब, उन्होंने प्लेटफॉर्म या कंपाइलर संस्करणों का कोई जिक्र नहीं किया है, जो एक वैध चिंता होगी यदि आप प्रत्येक रिमोट सर्वर / क्लाइंट पर समान ऑपरेशन चाहते हैं .... लेकिन यह उनके बयान से स्पष्ट नहीं है। एक बेहतर शब्द "भरोसेमंद समान" या कुछ हो सकता है। - Alice
@ एलिस आप semantics बहस करके, अपने आप सहित, हर किसी के समय बर्बाद कर रहे हैं। उनका अर्थ स्पष्ट था। - Lanaru
@ लानारू मानकों का पूरा बिंदु अर्थशास्त्र है; उसका अर्थ निश्चित रूप से स्पष्ट नहीं था। - Alice


मुझे उम्मीद नहीं थी कि इस मामले को अनुकूलित किया जा सके। यह अक्सर नहीं हो सकता है जहां एक अभिव्यक्ति में उप-अभिव्यक्तियां होती हैं जिन्हें पूरे परिचालन को हटाने के लिए पुन: समूहित किया जा सकता है। मैं संकलक लेखकों को उन क्षेत्रों में अपना समय निवेश करने की उम्मीद करूंगा जो शायद ही कभी सामना किए जाने वाले किनारे के मामले को कवर करने के बजाए ध्यान देने योग्य सुधारों के परिणामस्वरूप हों।

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

जैसा कि आपने यहां किया है, संकलक को संकेत प्रदान करने में कुछ भी गलत नहीं है। बयान और अभिव्यक्तियों को पुनर्व्यवस्थित करने के लिए माइक्रो-ऑप्टिमाइज़ेशन प्रक्रिया का यह एक सामान्य और अपेक्षित हिस्सा है, यह देखने के लिए कि वे क्या अंतर लाएंगे।

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


26
2018-01-03 16:40



जैसा कि एक और टिप्पणीकार ने उल्लेख किया है, यह बेतुका होने के बिंदु से असत्य है; अंतर लागत का आधा से 10% तक हो सकता है, और यदि एक तंग पाश में चलाया जाता है, तो यह अतिरिक्त परिशुद्धता की एक महत्वपूर्ण मात्रा में क्या हो सकता है, यह जानने के लिए बर्बाद कई निर्देशों का अनुवाद करेगा। यह कहकर कि आप मोंटे कार्लो कर रहे हैं तो मानक एफपी का उपयोग नहीं करना चाहिए, यह कहने की तरह है कि आपको हमेशा देश भर में एक हवाई जहाज का उपयोग करना चाहिए; यह कई बाहरीताओं को अनदेखा करता है। अंत में, यह एक असामान्य अनुकूलन नहीं है; मृत कोड विश्लेषण और कोड में कमी / रिफैक्टर बहुत आम है। - Alice