क्या x + = x = x + a की तुलना में तेज है?


84

मैं स्ट्रॉस्ट्रुप की "द सी ++ प्रोग्रामिंग लैंग्वेज" पढ़ रहा था, जहाँ वह कहता है कि किसी चर में कुछ जोड़ने के दो तरीकों में से

x = x + a;

तथा

x += a;

वह पसंद करता है +=क्योंकि यह सबसे बेहतर रूप से लागू होने की संभावना है। मुझे लगता है कि उनका मतलब है कि यह तेजी से भी काम करता है।
लेकिन क्या यह वास्तव में है? यदि यह संकलक और अन्य चीजों पर निर्भर करता है, तो मैं कैसे जांच करूं?


45
"सी ++ प्रोग्रामिंग लैंग्वेज" को पहली बार 1985 में प्रकाशित किया गया था। सबसे हालिया संस्करण 1997 में प्रकाशित हुआ था, और 1997 संस्करण का एक विशेष संस्करण 2000 में प्रकाशित हुआ था। परिणामस्वरूप, कुछ भाग बेहद पुराने हैं।
जोज

5
दोनों लाइनें संभावित रूप से कुछ पूरी तरह से अलग कर सकती हैं। आपको अधिक विशिष्ट होना चाहिए।
केरेक एसबी


26
इन प्रश्नों को 'पुराना' मानने के लिए आधुनिक कंपाइलर काफी स्मार्ट हैं।
19

2
इसे फिर से खोला गया क्योंकि डुप्लिकेट प्रश्न C नहीं C ++ के बारे में पूछता है।
केव

जवाबों:


212

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

यदि कथन अधिक जटिल है, हालांकि, वे भिन्न हो सकते हैं। मान लीजिए fकि एक फ़ंक्शन है जो एक पॉइंटर लौटाता है, तो

*f() += a;

fकेवल एक बार कॉल करता है , जबकि

*f() = *f() + a;

दो बार फोन करता है। यदि fसाइड इफेक्ट होते हैं, तो दोनों में से एक गलत होगा (शायद बाद वाला)। यहां तक ​​कि अगर fसाइड इफेक्ट नहीं होते हैं, तो कंपाइलर दूसरी कॉल को खत्म करने में सक्षम नहीं हो सकता है, इसलिए बाद वाला वास्तव में धीमा हो सकता है।

और जब से हम यहां C ++ के बारे में बात कर रहे हैं, तो क्लास के प्रकारों के लिए स्थिति पूरी तरह से अलग है जो अधिभार operator+और operator+=। यदि xऐसा कोई प्रकार है, तो - अनुकूलन से पहले - x += aअनुवाद करता है

x.operator+=(a);

जबकि x = x + aअनुवाद करता है

auto TEMP(x.operator+(a));
x.operator=(TEMP);

अब, यदि कक्षा ठीक से लिखी गई है और संकलक का अनुकूलक काफी अच्छा है, तो दोनों एक ही मशीन की भाषा उत्पन्न करेंगे, लेकिन यह सुनिश्चित नहीं है कि यह बिल्ट-इन प्रकारों के लिए है। शायद यही है कि स्ट्रॉस्ट्रुप सोच रहा है जब वह इसके इस्तेमाल को प्रोत्साहित करता है +=


14
एक और पहलू भी है - पठनीयता । जोड़ने के लिए सी ++ मुहावरा exprकरने के लिए varहै var+=exprऔर इसे लिखने के अन्य तरीके से पाठकों को भ्रमित करेंगे।
तेदुशे कोपेक

21
यदि आप अपने आप को लिख रहे हैं *f() = *f() + a;तो आप एक अच्छा कठिन रूप लेना चाहते हैं जो आप वास्तव में हासिल करने की कोशिश कर रहे हैं ...
एडम डेविस

3
और अगर var = var + expr आपको भ्रमित करता है, लेकिन var + = expr नहीं करता है, तो आप सबसे अजीब सॉफ्टवेयर इंजीनियर हैं जो मैंने कभी मिले हैं। या तो पठनीय हैं; बस यह सुनिश्चित करें कि आप सुसंगत हैं (और हम सभी op = का उपयोग करते हैं, इसलिए इसकी मूट वैसे भी = P)
WhozCraig

7
@PiotrDobrogost: सवालों के जवाब देने में क्या गलत है? किसी भी मामले में, यह प्रश्नकर्ता होना चाहिए जिसने डुप्लिकेट के लिए जांच की।
गोरक्षक

4
@PiotrDobrogost मुझे लगता है कि आप एक छोटे से हैं ... ईर्ष्या ... यदि आप डुप्लिकेट की तलाश में चारों ओर जाना चाहते हैं, तो इसके लिए जाएं। मैं, एक के लिए, दुपट्टे की तलाश के बजाय सवालों का जवाब देना पसंद करता हूं (जब तक कि यह एक ऐसा सवाल नहीं है जिसे मैं विशेष रूप से पहले देखा गया था)। यह कभी-कभी तेज हो सकता है, और ergo उस व्यक्ति की मदद करता है जिसने सवाल तेजी से पूछा था। यह भी ध्यान दें कि यह लूप भी नहीं है। 1एक स्थिर, aएक अस्थिर, एक उपयोगकर्ता-परिभाषित प्रकार, या जो कुछ भी हो सकता है। पूरी तरह से अलग। वास्तव में, मुझे समझ नहीं आता कि यह कैसे बंद हो गया।
लुचियन ग्रिगोर

56

आप असंतुष्ट को देखकर जांच कर सकते हैं, जो समान होगा।

बुनियादी प्रकारों के लिए , दोनों समान रूप से तेज़ हैं।

यह एक डिबग बिल्ड (यानी कोई अनुकूलन) द्वारा उत्पन्न आउटपुट है:

    a += x;
010813BC  mov         eax,dword ptr [a]  
010813BF  add         eax,dword ptr [x]  
010813C2  mov         dword ptr [a],eax  
    a = a + x;
010813C5  mov         eax,dword ptr [a]  
010813C8  add         eax,dword ptr [x]  
010813CB  mov         dword ptr [a],eax  

उपयोगकर्ता-परिभाषित प्रकारों के लिए , जहां आप अधिभार कर सकते हैं operator +और operator +=, यह उनके संबंधित कार्यान्वयन पर निर्भर करता है।


1
सभी मामलों में सच नहीं है। मैंने पाया है कि यह मेमोरी मेमोरी को एक रजिस्टर में लोड करने के लिए तेज़ हो सकता है, इसे बढ़ा सकता है, और इसे सीधे मेमोरी स्थान को बढ़ाने के लिए लिख सकता है (एटॉमिक्स का उपयोग नहीं कर रहा है)। मैं कोड
जेम्स

उपयोगकर्ता परिभाषित प्रकारों के बारे में कैसे? अच्छा संकलक समतुल्य विधानसभा उत्पन्न करना चाहिए , लेकिन ऐसी कोई गारंटी नहीं है।
mfontanini 14

1
@LuchianGrigore नहीं, अगर a1 और xहै volatileसंकलक उत्पन्न कर सकता है inc DWORD PTR [x]। यह धीमा है।
जेम्स

1
@ शिफा संकलक-निर्भर नहीं है, लेकिन डेवलपर-निर्भर है। आप operator +कुछ भी नहीं करने के लिए लागू कर सकते हैं , और operator +=100000 वें अभाज्य संख्या की गणना कर सकते हैं और फिर लौट सकते हैं। बेशक, यह करने के लिए एक बेवकूफ बात होगी, लेकिन यह संभव है।
लुचियन ग्रिगोर

3
@ नाम: यदि आपका प्रोग्राम प्रदर्शन अंतर के बीच समझदार है ++xऔर temp = x + 1; x = temp;, तो संभवतः इसे सी ++ के बजाय असेंबली में लिखा जाना चाहिए ...
इमरकैलाबच

11

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


8

यह वास्तव में x और a के प्रकार और + के कार्यान्वयन पर निर्भर करता है। के लिये

   T x, a;
   ....
   x = x + a;

संकलक को x + का मान रखने के लिए एक अस्थायी T बनाना पड़ता है, जबकि यह इसका मूल्यांकन करता है, जिसे वह बाद में x को निर्दिष्ट कर सकता है। (यह इस कार्य के दौरान x या एक कार्यक्षेत्र के रूप में उपयोग नहीं कर सकता है)।

X + = a के लिए, इसे अस्थायी की आवश्यकता नहीं है।

तुच्छ प्रकारों के लिए, कोई अंतर नहीं है।


8

के बीच का अंतर x = x + aऔर x += aकाम की राशि मशीन जाना पड़ता है के माध्यम से है - कुछ compilers (और आमतौर पर करते हैं) हो सकता है इसे दूर का अनुकूलन, लेकिन आम तौर पर, अगर हम थोड़ी देर के लिए अनुकूलन की अनदेखी, क्या होता है कि पूर्व कोड स्निपेट में, मशीन को xदो बार मान देखना पड़ता है , जबकि बाद वाले में, इस लुकअप को केवल एक बार होने की आवश्यकता होती है।

हालांकि, जैसा कि मैंने उल्लेख किया है, आज अधिकांश संकलक निर्देश का विश्लेषण करने और आवश्यक मशीन निर्देशों को कम करने के लिए पर्याप्त बुद्धिमान हैं।

पुनश्च: स्टैक ओवरफ्लो पर पहला जवाब!


6

जैसा कि आपने इस C ++ को लेबल किया है, आपके द्वारा पोस्ट किए गए दो कथनों से जानने का कोई तरीका नहीं है। आपको यह जानना होगा कि 'x' क्या है (यह उत्तर '42' जैसा है)। यदि xएक POD है, तो यह वास्तव में बहुत अंतर नहीं करने वाला है। हालांकि, अगर xएक वर्ग है, वहाँ के लिए भार के हो सकता है operator +और operator +=तरीकों जो कि नेतृत्व बहुत अलग निष्पादन समय के लिए अलग अलग व्यवहार हो सकता था।


6

यदि आप कहते हैं कि +=आप जीवन को संकलक के लिए बहुत आसान बना रहे हैं। कंपाइलर को पहचानने के x = x+aलिए उसी तरह x += aसे है जैसे कंपाइलर को होता है

  • बाएं हाथ का विश्लेषण करें ( x) यह सुनिश्चित करने के लिए कि इसका कोई साइड इफेक्ट नहीं है और हमेशा एक ही एल-मूल्य को संदर्भित करता है। उदाहरण के लिए, यह हो सकता है z[i], और यह सुनिश्चित करना है कि दोनों zऔर iनहीं बदलते हैं।

  • दाहिने हाथ की ओर ( x+a) का विश्लेषण करें और सुनिश्चित करें कि यह एक योग है, और यह कि बाएं हाथ की तरफ एक बार और केवल एक बार दाएं हाथ की तरफ होता है, भले ही इसे रूपांतरित किया जा सकता है, जैसे कि z[i] = a + *(z+2*0+i)

क्या आपका मतलब है जोड़ने के लिए है, तो aकरने के लिए x, संकलक लेखक यह की सराहना करता है जब तुम सिर्फ तुम क्या मतलब है कहना। इस तरह, आप कंपाइलर के उस हिस्से का प्रयोग नहीं कर रहे हैं, जिसके लेखक को उम्मीद है कि वह सभी बगों से बाहर निकल गया है, और यह वास्तव में आपके लिए जीवन को आसान नहीं बनाता है, जब तक कि आप ईमानदारी से अपना सिर बाहर नहीं निकाल सकते। फोरट्रान मोड के।


5

एक ठोस उदाहरण के लिए, एक साधारण जटिल संख्या प्रकार की कल्पना करें:

struct complex {
    double x, y;
    complex(double _x, double _y) : x(_x), y(_y) { }
    complex& operator +=(const complex& b) {
        x += b.x;
        y += b.y;
        return *this;
    }
    complex operator +(const complex& b) {
        complex result(x+b.x, y+b.y);
        return result;
    }
    /* trivial assignment operator */
}

A = a + b केस के लिए, उसे एक अतिरिक्त अस्थायी चर बनाना होगा और फिर उसे कॉपी करना होगा।


यह बहुत अच्छा उदाहरण है, दिखाता है कि 2 ऑपरेटरों ने कैसे लागू किया।
बृजेश चौहान

5

आप गलत सवाल पूछ रहे हैं।

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

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

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


दी गई, लेकिन इसका मतलब निम्न स्तर के प्रश्न के रूप में था, न कि एक बड़ी तस्वीर "जब मुझे इस तरह के अंतर पर विचार करना चाहिए"।
शिफा

1
ओपी का प्रश्न पूरी तरह से वैध था, जैसा कि अन्य उत्तरों (और अपवोट्स) द्वारा दिखाया गया है। यद्यपि हम आपकी बात (प्रोफ़ाइल पहले, आदि) प्राप्त करते हैं, यह निश्चित रूप से इस तरह के सामान को जानना दिलचस्प है - क्या आप वास्तव में प्रत्येक और प्रत्येक तुच्छ बयान को प्रोफाइल करने जा रहे हैं, जो आपके द्वारा लिए गए प्रत्येक निर्णय के परिणामों को प्रोफाइल करता है? यहां तक ​​कि जब एसओ पर ऐसे लोग हैं जिन्होंने पहले से ही अध्ययन किया है, प्रोफाइल किया है, मामले को खारिज कर दिया है और प्रदान करने के लिए एक सामान्य जवाब है?

4

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

mov $[y],$ACC

iadd $ACC, $[i] ; i += y. WHICH MIGHT ALSO STORE IT INTO "i"

जबकि, i = i + y(अनुकूलन के बिना) अनुवाद हो सकता है:

mov $[i],$ACC

mov $[y],$B 

iadd $ACC,$B

mov $B,[i]


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


2

नहीं, दोनों तरीके समान हैं।


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