2008-09-10 17 views
6

जो तेजी से कोड के लिए संकलित करता है: "ans = n * 3" या "ans = n + (n * 2)"?जो तेजी से कोड के लिए संकलित करता है: "एन * 3" या "एन + (एन * 2)"?

मान लीजिए कि एन या तो एक int या लंबा है, और यह एक आधुनिक Win32 इंटेल बॉक्स पर चल रहा है।

क्या कुछ अलग-अलग शामिल होने पर यह अलग होगा, यानी, इनमें से कौन सा तेज़ होगा?

 

long a; 
long *pn; 
long  ans; 

... 
*pn = some_number; 
ans = *pn * 3; 

या

 
ans = *pn+(*pn*2); 

या, यह कुछ एक के बारे में के रूप में के अनुकूलन compilers किसी भी मामले में इस के लिए खाते की संभावना है चिंता की जरूरत नहीं है?

उत्तर

55

आईएमओ ऐसे माइक्रो-ऑप्टिमाइज़ेशन आवश्यक नहीं है जब तक आप कुछ विदेशी कंपाइलर के साथ काम नहीं करते। मैं पहली जगह पर पठनीयता रखूंगा।

1

यह वास्तव में आपके द्वारा उपयोग किए जा रहे कंपाइलर पर निर्भर करता है, लेकिन शायद वे एक ही कोड में अनुवाद करते हैं।

आप एक छोटे से परीक्षण कार्यक्रम बनाकर और अपने disassembly की जांच करके इसे अपने आप से जांच सकते हैं।

1

अधिकांश कंप्यूटर्स बिट बदलावों और जोड़ों की एक श्रृंखला में एक पूर्णांक गुणा को विघटित करने के लिए पर्याप्त स्मार्ट हैं। मुझे विंडोज कंपाइलर्स के बारे में पता नहीं है, लेकिन कम से कम जीसीसी के साथ आप इसे असेंबलर थूकने के लिए प्राप्त कर सकते हैं, और यदि आप इसे देखते हैं तो आप शायद इसे लिखने के दोनों तरीकों के लिए समान असेंबलर देख सकते हैं।

0

कंपाइलर्स आपके जैसे कोड को अनुकूलित करने में अच्छे हैं। कोई भी आधुनिक कंपाइलर दोनों मामलों के लिए एक ही कोड उत्पन्न करेगा और अतिरिक्त बाएं शिफ्ट द्वारा * 2 को प्रतिस्थापित करेगा।

+0

इतना सुनिश्चित न करें :) मैंने एम्बेडेड सॉफ्टवेयर विकास के लिए कुछ वास्तव में अजीब कंपाइलर देखा। – aku

+1

एम्बेडेड सिस्टम में, लगभग सभी पारंपरिक ज्ञान समाप्त होता है। ;-) –

4

यह संकलक, इसकी कॉन्फ़िगरेशन और आसपास के कोड पर निर्भर करेगा।

आपको कोशिश नहीं करना चाहिए और अनुमान लगाया जाना चाहिए कि क्या माप मापने के बिना 'तेज' हैं।

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

10

चूंकि इसे स्वयं मापना आसान है, ऐसा क्यों नहीं करते? (Cygwin से gcc और time का उपयोग करना)

/* test1.c */ 
int main() 
{ 
    int result = 0; 
    int times = 1000000000; 
    while (--times) 
     result = result * 3; 
    return result; 
} 

machine:~$ gcc -O2 test1.c -o test1 
machine:~$ time ./test1.exe 

real 0m0.673s 
user 0m0.608s 
sys  0m0.000s 

बार के एक जोड़े के लिए परीक्षण करते हैं और अन्य मामले के लिए दोहराएँ।

आप विधानसभा कोड पर नज़र चाहते हैं, gcc -S -O2 test1.c

+0

दुर्भाग्यवश यह एक बुरा उदाहरण है - i686-apple-darwin8-gcc-4.0.1 के साथ, यह लूप से "परिणाम = परिणाम * 3" को पूरी तरह से हटा देता है क्योंकि यह हमेशा शून्य होता है। प्रारंभिक स्थिति को "परिणाम = 1" में बदलना बेहतर परिणाम देता है। –

+0

या बेहतर, यादृच्छिक संख्याओं की एक सरणी बनाएं और प्रक्रिया करें, इसलिए संकलक कोई धारणा नहीं कर सकता है। – DarenW

15

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

MUL EAX,3 

कार्यान्वित तेजी से

MOV EBX,EAX 
SHL EAX,1 
ADD EAX,EBX 

पिछले प्रोसेसर जहां अनुकूलन की इस तरह उपयोगी हो सकता है शायद था 486. (हाँ, यह इंटेल प्रोसेसर के लिए पक्षपाती है, लेकिन है शायद अन्य आर्किटेक्चर के प्रतिनिधि भी)।

किसी भी घटना में, कोई भी उचित कंपाइलर सबसे छोटा/तेज़ कोड उत्पन्न करने में सक्षम होना चाहिए। तो हमेशा पहले पठनीयता के साथ जाओ।

+3

मुझे वास्तव में संदेह है कि एमयूएल तेजी से निष्पादित हो जाता है, एक बार विलंबता और लचीलापन जिसके बारे में आप रजिस्ट्रार का उपयोग कर सकते हैं, को ध्यान में रखा जाता है। इसके अलावा x86, एलआईए पर, आपके द्वारा दिए गए 3-निर्देश अनुक्रम नहीं, 3 * एन और एन + 2 * एन दोनों के लिए किसी सभ्य कंपाइलर द्वारा उपयोग किया जाएगा। –

+1

सच है, लेकिन एलआईएल केवल तभी उपयोगी होता है जब स्थिरांक के छोटे सेट (2, 3, 4, 5, 8 और 9) द्वारा गुणा करके सही तरीके से याद किया जाता है)। वैसे भी मेरा मुद्दा संकलक को सबसे तेज़ कोड को समझने देना था। – Ferruccio

4

यह पता लगाना मुश्किल नहीं है कि संकलक आपके कोड के साथ क्या कर रहा है (मैं यहां DevStudio 2005 का उपयोग कर रहा हूं)। निम्नलिखित कोड के साथ एक सरल कार्यक्रम लिखें:

int i = 45, j, k; 
j = i * 3; 
k = i + (i * 2); 

मध्य रेखा पर ब्रेकपॉइंट रखें और डीबगर का उपयोग करके कोड चलाएं। जब ब्रेकपॉइंट ट्रिगर होता है, तो स्रोत फ़ाइल पर राइट क्लिक करें और "Disassembly पर जाएं" का चयन करें। अब आपके पास सीपीयू निष्पादित कोड वाला एक विंडो होगा। आप इस मामले में ध्यान देंगे कि पिछली दो पंक्तियां बिल्कुल वही निर्देश उत्पन्न करती हैं, अर्थात्, "लीए ईएक्स, [ईबीएक्स + ईबीएक्स * 2]" (इस विशेष मामले में थोड़ा स्थानांतरण और जोड़ना नहीं)। एक आधुनिक आईए 32 सीपीयू पर, सीपीयू की पाइपलाइनिंग प्रकृति के कारण बिट स्थानांतरण के बजाए सीधी एमयूएल करने के लिए शायद अधिक कुशल है जो जल्द ही एक संशोधित मूल्य का उपयोग करते समय जुर्माना लगाता है।

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

+0

मुझे पाइपलाइन एक मुद्दा नहीं है। अंकगणितीय इकाई शायद एक चरण में आंतरिक रूप से ईबीएक्स + ईबीएक्स * 2 को हेल कर सकती है। – Artelius

0

इस तरह के कोड के छोटे टुकड़ों को अनुकूलित करने के लिए अपने कंपाइलर पर भरोसा करें। कोड स्तर पर पठनीयता अधिक महत्वपूर्ण है। सही अनुकूलन उच्च स्तर पर आना चाहिए।

1

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

:-)

1

जब तक आप एक सभ्य अनुकूलन संकलक के रूप में प्रयोग कर रहे हैं, बस लिखने कोड आसान है कि संकलक को समझने के लिए। यह संकलक के लिए चालाक अनुकूलन करने के लिए आसान बनाता है।

आप यह प्रश्न पूछते हैं कि एक अनुकूलन कंपाइलर आपके से अनुकूलन के बारे में और जानता है। तो संकलक पर भरोसा करें। n * 3 का प्रयोग करें।

this answer पर भी एक नज़र डालें।