क्लैंग एक्स * 1.0 का अनुकूलन क्यों करता है लेकिन x + 0.0 नहीं?


125

क्लैंग इस कोड में लूप को ऑप्टिमाइज़ क्यों करता है

#include <time.h>
#include <stdio.h>

static size_t const N = 1 << 27;
static double arr[N] = { /* initialize to zero */ };

int main()
{
    clock_t const start = clock();
    for (int i = 0; i < N; ++i) { arr[i] *= 1.0; }
    printf("%u ms\n", (unsigned)(clock() - start) * 1000 / CLOCKS_PER_SEC);
}

लेकिन इस कोड में पाश नहीं?

#include <time.h>
#include <stdio.h>

static size_t const N = 1 << 27;
static double arr[N] = { /* initialize to zero */ };

int main()
{
    clock_t const start = clock();
    for (int i = 0; i < N; ++i) { arr[i] += 0.0; }
    printf("%u ms\n", (unsigned)(clock() - start) * 1000 / CLOCKS_PER_SEC);
}

(C और C ++ दोनों को टैग करना क्योंकि मैं जानना चाहूंगा कि क्या प्रत्येक के लिए उत्तर अलग है।


2
वर्तमान में कौन से अनुकूलन झंडे सक्रिय हैं?
इविलनोटिक्सिस्ट इडोनोटेक्सिस्ट

1
@IwillnotexistIdonotexist: मैंने अभी उपयोग किया है -O3, मुझे नहीं पता कि यह कैसे जांचना है कि हालांकि क्या सक्रिय होता है।
user541686

2
यह देखना दिलचस्प होगा कि यदि आप कमांड लाइन में -फास्ट-गणित जोड़ते हैं तो क्या होता है।
प्लग

static double arr[N]सी में अनुमति नहीं है; constचर उस भाषा में निरंतर अभिव्यक्तियों के रूप में नहीं गिने जाते हैं
एमएम

1
[इस बारे में भद्दी टिप्पणी डालें कि C कैसे C ++ नहीं है, भले ही आप इसे पहले ही कह चुके हों।]
user253751

जवाबों:


164

IEEE 754-2008 मानक फ़्लोटिंग-पॉइंट अंकगणित के लिए और ISO / IEC 10967 भाषा स्वतंत्र अंकगणित (LIA) मानक, भाग 1 उत्तर क्यों ऐसा है।

IEEE 754 The 6.3 साइन बिट

जब कोई इनपुट या परिणाम NaN होता है, तो यह मानक NaN के संकेत की व्याख्या नहीं करता है। ध्यान दें, हालांकि, बिट स्ट्रिंग्स पर कार्रवाई - कॉपी, नेगेट, एब्स, कॉपीसिग्न - एक NaN परिणाम के साइन बिट को निर्दिष्ट करते हैं, कभी-कभी एक NaN ऑपरेंड के साइन बिट पर आधारित होता है। तार्किक विधेय कुलऑर्डर एक NaN ऑपरेंड के साइन बिट से भी प्रभावित होता है। अन्य सभी कार्यों के लिए, यह मानक NaN परिणाम के संकेत बिट को निर्दिष्ट नहीं करता है, तब भी जब केवल एक इनपुट NaN हो, या जब NaN अमान्य ऑपरेशन से उत्पन्न होता हो।

जब न तो इनपुट और न ही परिणाम NaN होते हैं, तो किसी उत्पाद या भागफल का संकेत विशेष या ऑपरेंड के संकेत हैं; किसी राशि का अंतर, या अंतर x - y को एक योग x + (ay) के रूप में माना जाता है, जो कि अधिकांश जोड़ के संकेतों में से एक से भिन्न होता है; और रूपांतरणों के परिणाम का संकेत, परिमाणित संचालन, राउंडटॉ-इंटीग्रल ऑपरेशंस, और राउंडटॉइंटरग्लैक्टैक्ट (5.3.1 देखें) पहले या एकमात्र ऑपरेंड का संकेत है। ये नियम तब भी लागू होंगे जब संचालन या परिणाम शून्य या अनंत हों।

जब विपरीत संकेतों वाले दो ऑपरेंड (या संकेतों जैसे दो ऑपरेंड्स का अंतर) बिल्कुल शून्य हो, तो राउंडटाउडरनेटिव को छोड़कर सभी राउंडिंग-दिशा विशेषताओं में उस योग (या अंतर) का चिह्न +0 होगा; उस विशेषता के तहत, एक सटीक शून्य राशि (या अंतर) का चिह्न sign0 होगा। हालाँकि, x + x = x - (xx) x के शून्य होने पर भी उसी चिह्न को x बनाए रखता है।

जोड़ का मामला

डिफ़ॉल्ट राउंडिंग मोड के तहत (राउंड-टू-नेस्ट, टीज़-टू-इवन) , हम देखते हैं कि x+0.0उत्पादन करता है x, EXCEPT कब xहै -0.0: उस स्थिति में हमारे पास विपरीत संकेतों वाले दो ऑपरेंड का योग है जिसका योग शून्य है, और .36- पैरा इसके अतिरिक्त 3 नियम उत्पन्न होते हैं +0.0

चूंकि मूल के समान बिटवाइज़+0.0 नहीं है , और यह एक वैध मूल्य है जो इनपुट के रूप में हो सकता है, संकलक को कोड में डालने के लिए बाध्य किया जाता है जो संभावित नकारात्मक शून्य को बदल देगा ।-0.0-0.0+0.0

सारांश: डिफ़ॉल्ट गोलाई मोड के तहत, में x+0.0, अगरx

  • नहीं है -0.0 , तो xअपने आप में एक स्वीकार्य आउटपुट वैल्यू है।
  • है -0.0 , तो आउटपुट वैल्यू होना चाहिए +0.0 , जो बिटवाइज़ के समान नहीं है -0.0

गुणन का मामला

डिफ़ॉल्ट राउंडिंग मोड के तहत , ऐसी कोई समस्या नहीं होती है x*1.0। यदि x:

  • एक (उप) सामान्य संख्या है, x*1.0 == xहमेशा।
  • है +/- infinity, तो परिणाम +/- infinityउसी संकेत का है।
  • के NaNअनुसार है

    IEEE 754 4 6.2.3 NaN प्रसार

    एक ऑपरेशन जो अपने परिणाम के लिए एक NaN ऑपरेंड का प्रचार करता है और एक एकल NaN होता है इनपुट के रूप में एक NaN इनपुट NaN के पेलोड के साथ उत्पादन करना चाहिए यदि गंतव्य प्रारूप में प्रतिनिधित्व योग्य है।

    जिसका अर्थ है कि प्रतिपादक और अपूर्णांश (हालांकि नहीं चिह्न) का NaN*1.0कर रहे हैं की सिफारिश की इनपुट से अपरिवर्तित होने के लिए NaN। संकेत ऊपर is6.3p1 के अनुसार अनिर्दिष्ट है, लेकिन एक कार्यान्वयन इसे स्रोत के समान होने के लिए निर्दिष्ट कर सकता है NaN

  • है +/- 0.0, तो परिणाम एक है 0का संकेत बिट के साथ XORed थोड़ा अपने हस्ताक्षर के साथ 1.0§6.3p2 के साथ समझौते में,। चूंकि साइन बिट 1.0है 0, आउटपुट मान इनपुट से अपरिवर्तित है। इस प्रकार, x*1.0 == xतब भी जब xशून्य (ऋणात्मक) शून्य हो।

घटाव का मामला

डिफ़ॉल्ट राउंडिंग मोड के तहत , घटाव x-0.0भी एक नो-ऑप है, क्योंकि यह इसके बराबर है x + (-0.0)। अगर xहै

  • है NaN, तो ,6.3p1 और then6.2.3 इसके अलावा और गुणा के लिए एक ही तरीके से लागू होते हैं।
  • है +/- infinity, तो परिणाम +/- infinityउसी संकेत का है।
  • एक (उप) सामान्य संख्या है, x-0.0 == xहमेशा।
  • है -0.0, तो p6.3p2 से हमारे पास " [...] एक राशि का चिह्न है, या एक अंतर x - y को एक योग x + ()y) के रूप में माना जाता है, जो कि अधिकांश जोड़ियों के संकेतों में से एक से भिन्न होता है; "। यह हमें -0.0परिणाम के रूप में असाइन करने के लिए मजबूर करता है (-0.0) + (-0.0), क्योंकि इस खंड के उल्लंघन में, जोड़ में -0.0से किसी एक से साइन में भिन्नता नहीं है, जबकि दो में +0.0से अलग से साइन इन करता है ।
  • इसके +0.0बाद, यह द केस ऑफ एडिशन(+0.0) + (-0.0) में ऊपर विचार किए गए अतिरिक्त मामले को कम करता है , जिसे this6.3p3 द्वारा देने का फैसला किया जाता है ।+0.0

चूंकि सभी मामलों के लिए इनपुट मूल्य आउटपुट के रूप में कानूनी है, इसलिए इसे x-0.0नो-ऑप और x == x-0.0एक टॉटोलॉजी पर विचार करने की अनुमति है।

मूल्य-परिवर्तन अनुकूलन

IEEE 754-2008 स्टैंडर्ड में निम्नलिखित दिलचस्प उद्धरण हैं:

IEEE 754 4 10.4 शाब्दिक अर्थ और मूल्य-परिवर्तन अनुकूलन

[...]

निम्नलिखित मूल्य-परिवर्तन परिवर्तन, दूसरों के बीच, स्रोत कोड के शाब्दिक अर्थ को संरक्षित करते हैं:

  • पहचान गुण 0 + x को लागू करना जब x शून्य नहीं है और एक संकेतन NaN नहीं है और परिणाम में x के समान घातांक है।
  • पहचान गुण 1 × x को लागू करना जब x संकेतन NaN नहीं है और परिणाम में x के समान प्रतिपादक है।
  • एक शांत NaN का पेलोड या साइन बिट बदलना।
  • [...]

सभी Nans और सभी infinities ही प्रतिपादक, और की सही ढंग से गोल परिणाम का हिस्सा के बाद से x+0.0और x*1.0परिमित के लिए xठीक उसी परिमाण के रूप में है x, उनके प्रतिपादक एक ही है।

sNaNs

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

हालांकि, जैसा कि user2357112 टिप्पणियों में बताते हैं , C11 मानक स्पष्ट रूप से NaNs ( sNaN) को संकेत देने के व्यवहार को अपरिभाषित करता है , इसलिए संकलक को यह मानने की अनुमति है कि वे घटित नहीं होते हैं, और इस प्रकार जो अपवाद हैं वे भी घटित नहीं होते हैं। C ++ 11 मानक NaNs को इंगित करने के लिए एक व्यवहार का वर्णन करते हुए छोड़ देता है, और इस तरह इसे अपरिभाषित भी छोड़ देता है।

राउंडिंग मोड्स

वैकल्पिक राउंडिंग मोड में, अनुमेय अनुकूलन बदल सकते हैं। उदाहरण के लिए, राउंड-नेगेटिव-इन्फिनिटी मोड के तहत , अनुकूलन x+0.0 -> xअनुमेय हो जाता है, लेकिन x-0.0 -> xनिषिद्ध हो जाता है।

जीसीसी को डिफ़ॉल्ट राउंडिंग मोड और व्यवहार को संभालने से रोकने के लिए, प्रयोगात्मक ध्वज -frounding-mathको जीसीसी को पारित किया जा सकता है।

निष्कर्ष

Clang और GCC , यहां तक ​​कि -O3IEEE-754 के अनुरूप है। इसका मतलब यह IEEE-754 मानक के उपरोक्त नियमों के अनुसार होना चाहिए। x+0.0है थोड़ा-समान नहीं करने के लिए xसभी के लिए xउन नियमों के तहत है, लेकिन x*1.0 ऐसा हो चुना जा सकता है : जब हम, अर्थात्

  1. xजब यह एक NaN है , तो पेलोड को अपरिवर्तित पारित करने की सिफारिश का पालन करें ।
  2. एक NaN परिणाम के संकेत बिट को अपरिवर्तित छोड़ दें * 1.0
  3. किसी भागफल / उत्पाद के दौरान साइन बिट को XOR करने के आदेश का पालन करें, जब xवह NaN नहीं है।

IEEE-754-असुरक्षित अनुकूलन को सक्षम करने के लिए (x+0.0) -> x, ध्वज -ffast-mathको Clang या GCC को पास करने की आवश्यकता होती है।


2
कैविएट: अगर यह एक संकेतन NaN है तो क्या होगा? (मैं वास्तव में सोचा था कि किसी तरह कारण हो सकता है, लेकिन मैं वास्तव में कैसे पता नहीं था, इसलिए मैंने पूछा।)
user541686

6
@ मेहरदाद: सी मानक का एक वैकल्पिक (वैकल्पिक) हिस्सा, जो IEEE 754 में सी पालन को स्पष्ट करता है, स्पष्ट रूप से संकेतन NaN को कवर नहीं करता है। (C11 F.2.1।, पहली पंक्ति: "यह विनिर्देश NaNs को इंगित करने के व्यवहार को परिभाषित नहीं करता है।") अनुलग्नक F के अनुरूप घोषणा करने वाले कार्यान्वयन वे करने के लिए स्वतंत्र हैं जो वे NaN को संकेत देने के साथ करना चाहते हैं। C ++ मानक की IEEE 754 की अपनी हैंडलिंग है, लेकिन जो कुछ भी है (मैं परिचित नहीं हूं), मुझे संदेह है कि यह NaN व्यवहार को भी इंगित करता है।
user2357112

2
@ मेहरदाद: sNaN मानक के अनुसार अपरिभाषित व्यवहार को आमंत्रित करता है (लेकिन यह शायद मंच द्वारा अच्छी तरह से परिभाषित किया गया है) इसलिए यहाँ संकलक स्क्वाशिंग की अनुमति है।
जोशुआ

1
@ user2357112: अन्यथा अप्रयुक्त गणना के लिए साइड-इफेक्ट के रूप में त्रुटि-फंसाने की संभावना आमतौर पर बहुत सारे अनुकूलन के साथ हस्तक्षेप करती है; यदि गणना के परिणाम को कभी-कभी नजरअंदाज कर दिया जाता है, तो एक संकलक उपयोगी रूप से गणना को स्थगित कर सकता है जब तक कि यह नहीं जान सकता है कि परिणाम का उपयोग किया जाएगा, लेकिन यदि गणना ने एक महत्वपूर्ण संकेत का उत्पादन किया होगा, तो यह खराब हो सकता है।
सुपरकैट

2
ओह देखो, एक प्रश्न जो वैध रूप से C और C ++ दोनों पर लागू होता है, जो एक ही मानक के संदर्भ में दोनों भाषाओं के लिए सटीक रूप से उत्तर दिया गया है। क्या यह लोगों को C और C ++ दोनों के साथ टैग किए गए प्रश्नों के बारे में शिकायत करने की संभावना कम कर देगा, भले ही प्रश्न एक भाषा समानता से संबंधित हो? दुख की बात है, मुझे नहीं लगता।
काइल स्ट्रैंड

35

x += 0.0यदि नहीं है, तो कोई एनओपी नहीं xहै -0.0। आशावादी पूरे पाश को वैसे भी बाहर निकाल सकता है क्योंकि परिणाम का उपयोग नहीं किया जाता है, हालांकि। सामान्य तौर पर, यह बताना मुश्किल है कि एक ऑप्टिमाइज़र निर्णय क्यों करता है।


2
मैं वास्तव में इसे पोस्ट करने के बाद मैंने अभी-अभी पढ़ा है कि क्यों x += 0.0नहीं नो-ऑप है, फिर भी मैंने सोचा कि शायद इसका कारण नहीं है क्योंकि पूरे लूप को किसी भी तरह से अनुकूलित किया जाना चाहिए। मैं इसे खरीद सकता हूं, यह पूरी तरह से आश्वस्त नहीं है जैसा कि मैं उम्मीद कर रहा था ...
user541686

ऑब्जेक्ट-ओरिएंटेड भाषाओं के साइड-इफेक्ट्स का उत्पादन करने की प्रवृत्ति को देखते हुए, मुझे लगता है कि यह सुनिश्चित करना मुश्किल होगा कि आशावादी वास्तविक व्यवहार नहीं है।
रॉबर्ट हार्वे

कारण हो सकता है, चूंकि long longअनुकूलन प्रभाव में है (इसे gcc के साथ किया है, जो कम से कम डबल के लिए समान व्यवहार करता है )
e2-e4

2
@ ringø: long longएक अभिन्न प्रकार है, न कि IEEE754 प्रकार।
MSalters

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