कौन सा तेजी से निष्पादित करेगा, यदि (झंडा == 0) या यदि (0 == ध्वज)?


111

साक्षात्कार प्रश्न: कौन सा तेजी से निष्पादित करेगा, if (flag==0)या if (0==flag)? क्यों?


330
कभी बेवकूफी से भरे साक्षात्कार के लिए नामांकित। और कड़ी प्रतिस्पर्धा है।
कोनराड रुडोल्फ

119
आप: ऐसी स्थिति का नाम बताइए, जहाँ इन दोनों के बीच का अंतर संभवतः परेशान करने लायक हो सकता है। साक्षात्कारकर्ता: ठीक है, आपको काम पर रखा गया है।
क्रिस लुत्ज़

37
दोनों के बीच एकमात्र अंतर यह है कि बाद के अधिवेशन के साथ, आपको if(flag = 0)थोड़ा पठनीयता की कीमत पर कीड़े के खिलाफ बीमा किया जाता है।
अमरघोष

22
@Amarghosh: अपने कोड को पढ़ने और अनपेक्षित करने के लिए कठिन बनाने की कीमत पर। अपने कंपाइलर चेतावनियों को चालू करें, जीतें-जीतें।
GManNickG

129
एक बार एक संकलक लेखक को अपने साक्षात्कार में यह मिला। उन्होंने जवाब में फुसफुसाए, "जो कोई एक कार्य करें आप तेजी से होना चाहते हैं?"।

जवाबों:


236

मैंने अभी तक कोई सही उत्तर नहीं देखा है (और पहले से ही कुछ) कैविएट हैं: नवाज ने उपयोगकर्ता द्वारा परिभाषित जाल को इंगित किया । और मुझे खेद है कि मैंने जल्दबाजी में "बेवकूफी भरे सवाल" पर उतारू हो गए क्योंकि ऐसा लगता है कि बहुतों को यह सही नहीं लगा और यह कंपाइलर ऑप्टिमाइज़ेशन पर एक अच्छी चर्चा के लिए जगह देता है :)

उत्तर है:

flagप्रकार क्या है ?

मामले में जहां flagवास्तव में एक उपयोगकर्ता-परिभाषित प्रकार है। फिर यह निर्भर करता है कि किस अधिभार का operator==चयन किया गया है। बेशक यह मूर्खतापूर्ण लग सकता है कि वे सममित नहीं होंगे, लेकिन यह निश्चित रूप से अनुमत है, और मैंने पहले ही अन्य गालियां देखी हैं।

यदि flagएक अंतर्निर्मित है, तो दोनों को समान गति लेनी चाहिए।

से विकिपीडिया लेख पर x86, मैं एक के लिए शर्त होगी Jxxके लिए अनुदेश ifबयान: शायद एक JNZ(कूद अगर नहीं शून्य) या कुछ बराबर।

मुझे संदेह है कि संकलक ऐसे स्पष्ट अनुकूलन को याद करता है, भले ही अनुकूलन बंद हो गया हो। यह उन चीजों का प्रकार है जिनके लिए पीपहोल ऑप्टिमाइज़ेशन के लिए डिज़ाइन किया गया है।

संपादित करें: फिर से ऊपर आ गया, तो चलो कुछ विधानसभा (LLVM 2.7 IR) जोड़ें

int regular(int c) {
  if (c == 0) { return 0; }
  return 1;
}

int yoda(int c) {
  if (0 == c) { return 0; }
  return 1;
}

define i32 @regular(i32 %c) nounwind readnone {
entry:
  %not. = icmp ne i32 %c, 0                       ; <i1> [#uses=1]
  %.0 = zext i1 %not. to i32                      ; <i32> [#uses=1]
  ret i32 %.0
}

define i32 @yoda(i32 %c) nounwind readnone {
entry:
  %not. = icmp ne i32 %c, 0                       ; <i1> [#uses=1]
  %.0 = zext i1 %not. to i32                      ; <i32> [#uses=1]
  ret i32 %.0
}

यहां तक ​​कि अगर कोई आईआर पढ़ना नहीं जानता है, तो मुझे लगता है कि यह स्वयं व्याख्यात्मक है।


4
@ मैथ्यू: आपने कहा कि मैंने अभी तक कोई सही उत्तर नहीं देखा है .. लेकिन मेरा सही है, मुझे लगता है: पी
नवाज

7
अच्छा! आपका उत्तर संभव है "मूर्खतापूर्ण सवाल" को "चालबाजी / मतलबी"। "चलो उम्मीदवार के लिए एक छेद खोदें और देखें कि क्या वह उसमें गिरता है ..." :) मुझे लगता है कि हम सभी स्वचालित रूप से मान लेते हैं कि flagपूर्णांक या मूल होना चाहिए। OTOH, flagएक उपयोगकर्ता-परिभाषित प्रकार का एक चर नाम है, अपने आप में काफी गलत है, IMHO
davka

@ नवाज़: मैंने आपके उत्तर के अंतिम पैराग्राफ को छोड़ दिया है: p
Matthieu M.

1
@ नवाज़: मैं वास्तव में दौड़ नहीं करता, मैं आमतौर पर सवालों के जवाब देने के बाद लंबे समय तक पढ़ता हूं और लोग केवल सबसे पहले उत्कीर्ण उत्तरों को पढ़ते हैं :) लेकिन मैं वास्तव में कंपाइलर ऑप्टिमाइज़ेशन पर सामान पढ़ रहा हूं, और इसने मुझे मारा तुच्छ अनुकूलन का विशिष्ट मामला तो मुझे लगा कि मैं इसे उन पाठकों के लिए इंगित करूंगा जो वास्तव में परेशान करते हैं ... मैं वास्तव में बहुत आश्चर्यचकित हूं कि मुझे बहुत सारे उत्थान मिले। अब यह मेरा सबसे अधिक मत वाला उत्तर है, हालांकि यह निश्चित रूप से ऐसा नहीं है, जिसमें मैंने सबसे अधिक प्रयास किया है: / वैसे भी मैंने अपना उत्तर संपादित किया और अपना वक्तव्य सही किया :)
Matthieu M.

2
@mr_eclair: एक अंतर्निहित प्रकार एक प्रकार है जो भाषा में अंतर्निहित (जैसा कि नाम निहित) है। यानी यह बिना किसी #includeनिर्देश के भी उपलब्ध है । सादगी के लिए, यह आम तौर पर के बराबर है int, char, boolऔर पसंद है। सभी अन्य प्रकार, उपयोगकर्ता परिभाषित होने के लिए कहा जाता है कि वे मौजूद हैं, क्योंकि वे उन्हें घोषित कुछ उपयोगकर्ता के परिणाम हैं: typedef, enum, struct, class। उदाहरण के लिए, std::stringउपयोगकर्ता परिभाषित है, भले ही आप निश्चित रूप से इसे स्वयं परिभाषित नहीं करते हैं :)
मथ्यू एम।

56

GCC 4.1.2 के साथ amd64 के लिए समान कोड:

        .loc 1 4 0  # int f = argc;
        movl    -20(%rbp), %eax
        movl    %eax, -4(%rbp)
        .loc 1 6 0 # if( f == 0 ) {
        cmpl    $0, -4(%rbp)
        jne     .L2
        .loc 1 7 0 # return 0;
        movl    $0, -36(%rbp)
        jmp     .L4
        .loc 1 8 0 # }
 .L2:
        .loc 1 10 0 # if( 0 == f ) {
        cmpl    $0, -4(%rbp)
        jne     .L5
        .loc 1 11 0 # return 1;
        movl    $1, -36(%rbp)
        jmp     .L4
        .loc 1 12 0 # }
 .L5:
        .loc 1 14 0 # return 2;
        movl    $2, -36(%rbp)
 .L4:
        movl    -36(%rbp), %eax
        .loc 1 15 0 # }
        leave
        ret

18
अतिरिक्त मील जाने के लिए +1 यह साबित करने के लिए कि कंपाइलर ऑप्टिमाइज़ेशन समान है।
k रे रे

56

आपके संस्करणों में कोई अंतर नहीं होगा।

मैं मान रहा हूं कि typeध्वज का प्रकार उपयोगकर्ता-परिभाषित प्रकार नहीं है, बल्कि यह कुछ अंतर्निहित प्रकार है। एनम अपवाद है! । आप एनम का इलाज कर सकते हैं जैसे कि यह बिल्ट-इन है। वास्तव में, यह 'बिल्ट-इन प्रकारों में से एक है!

मामले में, यदि यह उपयोगकर्ता-परिभाषित प्रकार (को छोड़कर enum) है, तो उत्तर पूरी तरह से इस बात पर निर्भर करता है कि आपने ऑपरेटर को कैसे अधिभारित किया है ==। ध्यान दें कि आपको अपने ==प्रत्येक संस्करण के लिए दो कार्यों को परिभाषित करके ओवरलोड करना है!


8
इस सवाल को पूछने का एकमात्र संभावित कारण हो सकता है, IMHO
davka

15
मुझे बहुत आश्चर्य होगा अगर आधुनिक संकलक इस तरह के एक स्पष्ट अनुकूलन से चूक गए।
पेड्रो डी'क्विनो

3
मेरी समझ से तो ! एक बिटवाइज़ ऑपरेशन नहीं है
जेवियर कॉम्बेल

8
@ नवाज़: हार नहीं मानी, लेकिन आपका जवाब तथ्यात्मक रूप से गलत है और यह बहुत ही भयानक है कि इसे अभी भी बहुत सारे बदलाव मिले हैं। रिकॉर्ड के लिए, पूर्णांक को 0 से तुलना करना एक एकल विधानसभा निर्देश है , पूरी तरह से निषेध के साथ सममूल्य पर। वास्तव में, यदि कंपाइलर थोड़ा बेवकूफ है, तो यह नकार से भी तेज हो सकता है (हालांकि संभावना नहीं है)।
कोनराड रुडोल्फ

6
@ नवाज़: यह कहना अभी भी गलत है कि यह तेज़ हो सकता है या होगा। यदि कोई अंतर है, तो "शून्य के खिलाफ तुलना करें" संस्करण तेजी से होगा, क्योंकि निषेधाज्ञा वास्तव में दो ऑपरेशनों में अनुवाद करती है: "निगेटिव ऑपरेंड; जांच करें कि परिणाम नॉनजरो है"। व्यवहार में, निश्चित रूप से, कंपाइलर इसे "शून्य के साथ तुलना" संस्करण के समान कोड का उत्पादन करने के लिए अनुकूलित करता है, लेकिन अनुकूलन को नकारात्मक संस्करण में लागू किया जा रहा है, इसे पकड़ने के लिए, और चारों ओर अन्य तरीके से नहीं। कोनराड सही है।
jalf

27

बिल्कुल कोई अंतर नहीं है।

आप असाइनमेंट / तुलना टाइपो के उन्मूलन का उल्लेख करके उस साक्षात्कार प्रश्न का उत्तर देने में अंक प्राप्त कर सकते हैं, हालांकि:

if (flag = 0)  // typo here
   {
   // code never executes
   }

if (0 = flag) // typo and syntactic error -> compiler complains
   {
   // ...
   }

हालांकि यह सच है, जैसे कि पूर्व के मामले में एक सी-कंपाइलर चेतावनी देता है ( flag = 0), PHP, पर्ल या जावास्क्रिप्ट या ऐसी कोई चेतावनी नहीं है <insert language here>


@ माथिउ हु। मुझे मेटा पर "उचित" ब्रेसिंग स्टाइल का वर्णन करते हुए पोस्ट याद आ गई होगी ।
लाइनस क्लेन

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

3
लोगों को बिना किसी कारण के वोट देने के लिए स्वतंत्र होना चाहिए। प्रतिष्ठा-वार, यह लगभग हमेशा एक अच्छी बात है क्योंकि यह अक्सर अन्य लोगों को उकसाने के लिए उकसाता है, अवांछनीय डाउनवोट के लिए मुकाबला करने के लिए, जब वास्तव में, एक एकल अपवोट पांच अवांछित डाउनवॉट को रद्द कर देगा।
डेविड हेडलंड

26
@ डेविड: डाउनवोटर्स को खुद को समझाना चाहिए क्योंकि यह साइट गुप्त लोकप्रियता मतपत्रों, अनाम मतदान या पसंद के बारे में नहीं है। यह साइट सीखने के बारे में है। अगर कोई यह कहता है कि एक प्रतिक्रिया गलत है, तो इसे गलत साबित करने के लिए, यदि वे इसे क्यों नहीं समझाते हैं, तो अपमान करने वाले को अपने ज्ञान के साथ स्वार्थी होना पड़ता है। वे सही होने पर सभी क्रेडिट लेने के लिए तैयार हैं, लेकिन दूसरों के गलत होने पर ज्ञान साझा करने के लिए तैयार नहीं हैं।
जॉन डिबलिंग 13

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

16

बिल्कुल अंतर गति-वार नहीं होगा। क्यों होना चाहिए?


7
यदि कंपाइलर पूरी तरह से मंद था। यही एकमात्र कारण है।
जेरेमीप

@JeremyP: कंपाइलर के मंद होने पर भी मैं अंतर की कल्पना नहीं कर सकता। संकलक लेखक को उद्देश्य पर करना होगा जहाँ तक मैं बता सकता हूँ।
जॉन

2
यह मानते हुए कि प्रोसेसर का "परीक्षण है यदि 0" निर्देश, x == 0इसका उपयोग कर 0 == xसकता है लेकिन एक सामान्य तुलना का उपयोग कर सकता है। मैंने कहा कि इसे मंदबुद्धि होना पड़ेगा।
जेरेमीप

8
यदि ध्वज एक उपयोगकर्ता-परिभाषित प्रकार है जो ऑपरेटर == () के असममित अधिभार के साथ है तो
ऑरेंजडॉग

क्योंकि हम एक उपयोगकर्ता-परिभाषित प्रकार में हो सकते हैं virtual operator==(int)?
लॉरो जू

12

अच्छी तरह से एक अंतर है जब झंडा एक उपयोगकर्ता परिभाषित प्रकार है

struct sInt
{
    sInt( int i ) : wrappedInt(i)
    {
        std::cout << "ctor called" << std::endl;
    }

    operator int()
    {
        std::cout << "operator int()" << std::endl;
        return wrappedInt;
    }

    bool operator==(int nComp)
    {
        std::cout << "bool operator==(int nComp)" << std::endl;
        return (nComp == wrappedInt);
    }

    int wrappedInt;
};

int 
_tmain(int argc, _TCHAR* argv[])
{
    sInt s(0);

    //in this case this will probably be faster
    if ( 0 == s )
    {
        std::cout << "equal" << std::endl;
    }

    if ( s == 0 )
    {
        std::cout << "equal" << std::endl;
    }
}

पहले मामले में (0 == s) रूपांतरण ऑपरेटर कहा जाता है और फिर लौटा परिणाम की तुलना 0. की जाती है। दूसरे मामले में == ऑपरेटर को कहा जाता है।


3
+1 यह उल्लेख करने के लिए कि रूपांतरण ऑपरेटर ऑपरेटर == के रूप में प्रासंगिक हो सकता है।
टोनी डेलारॉय

11

जब संदेह में यह बेंचमार्क और सच जानने के लिए।


2
बेंचमार्किंग में क्या गड़बड़ है? कभी-कभी अभ्यास आपको सिद्धांत से अधिक बता रहा है
एल्जो वलूगी

1
यही उत्तर मैं देख रहा था जब मैंने इस सूत्र को पढ़ना शुरू किया। ऐसा लगता है कि सिद्धांत अभ्यास की तुलना में अधिक आकर्षक है, जवाब और उत्थान देख रहे हैं :)
शमूएल रिवास

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

वे इस सवाल का सही उत्तर देते हैं (IMO) "यह बहुत कंपाइलर और बाकी प्रोग्राम पर निर्भर करता है। मैं एक बेंचमार्क लिखूंगा और 5 मिनट में इसका परीक्षण करूंगा"
सैमुअल रिवास

7

वे गति के मामले में बिल्कुल समान होना चाहिए।

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

if(flag=0) // <--- typo: = instead of ==; flag is now set to 0
{
    // this is never executed
}

if(0=flag) // <--- compiler error, cannot assign value to literal
{

}

दूसरी ओर, ज्यादातर लोग "योदा सशर्त" अजीब-दिखने वाले और परेशान होते हैं, खासकर जब से वे त्रुटियों को रोकते हैं, उन्हें पर्याप्त संकलक चेतावनी का उपयोग करके भी देखा जा सकता है।

if(flag=0) // <--- warning: assignment in conditional expression
{

}

गूँजने के लिए धन्यवाद। ध्यान दें, हालांकि, उदाहरण के लिए PHP सशर्त में असाइनमेंट के मामले में चेतावनी नहीं देगा।
लाइनस क्लेन

5

जैसा कि दूसरों ने कहा है, कोई अंतर नहीं है।

0मूल्यांकन किया जाना है। flagमूल्यांकन किया जाना है। इस प्रक्रिया में एक ही समय लगता है, कोई फर्क नहीं पड़ता कि वे किस पक्ष में हैं।

सही उत्तर होगा: वे दोनों समान गति वाले हैं।

यहाँ तक कि भाव if(flag==0)और if(0==flag)वर्णों की मात्रा समान है! यदि उनमें से एक के रूप में लिखा गया था if(flag== 0), तो संकलक के पास पार्स करने के लिए एक अतिरिक्त स्थान होगा, इसलिए आपके पास संकलन समय को इंगित करने का एक वैध कारण होगा।

लेकिन चूंकि ऐसी कोई बात नहीं है, इसलिए पूरी तरह से कोई कारण नहीं है कि किसी को दूसरे की तुलना में तेज होना चाहिए। यदि कोई कारण है, तो संकलक उत्पन्न कोड के लिए कुछ बहुत, बहुत अजीब चीजें कर रहा है ...


5

कौन सा उपवास निर्भर करता है = किस संस्करण का उपयोग कर रहे हैं। यहां एक स्निपेट दिया गया है जिसमें == के 2 संभावित कार्यान्वयन का उपयोग किया गया है, और इस पर निर्भर करता है कि आप x == 0 या 0 == x में से किसी एक को चुनना चाहते हैं या नहीं।

यदि आप अभी POD का उपयोग कर रहे हैं तो यह वास्तव में तब नहीं होना चाहिए जब यह गति की बात आती है।

#include <iostream>
using namespace std;

class x { 
  public:
  bool operator==(int x) { cout << "hello\n"; return 0; }
  friend bool operator==(int x, const x& a) { cout << "world\n"; return 0; } 
};

int main()
{ 
   x x1;
   //int m = 0;
   int k = (x1 == 0);
   int j = (0 == x1);
}

5

खैर, मैं ओपी के लिए टिप्पणियों में पूरी तरह से सहमत हूं, व्यायाम के लिए:

यदि कंपाइलर पर्याप्त चालाक नहीं है (वास्तव में आपको इसका उपयोग नहीं करना चाहिए) या अनुकूलन अक्षम है, तो x == 0एक मूल असेंबली jump if zeroइंस्ट्रक्शन को संकलित 0 == xकर सकता है , जबकि संख्यात्मक मूल्यों की तुलना में अधिक सामान्य (और महंगा) हो सकता है।

फिर भी, मैं ऐसे बॉस के लिए काम नहीं करना चाहूंगा जो इन शब्दों में सोचता हो ...


4

निष्पादन की गति के संदर्भ में निश्चित रूप से कोई अंतर नहीं है। हालत को दोनों मामलों में एक ही तरीके से मूल्यांकन करने की आवश्यकता है।


3

मुझे लगता है कि सबसे अच्छा जवाब "यह किस भाषा में उदाहरण है"?

प्रश्न में भाषा निर्दिष्ट नहीं थी और यह 'C' और 'C ++' दोनों को टैग किया गया था। एक सटीक उत्तर के लिए अधिक जानकारी की आवश्यकता होती है।

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


3

सुझाए गए तरीकों का उपयोग करके दो सरल प्रोग्राम बनाएं।

कोड इकट्ठा करें। विधानसभा को देखो और आप न्याय कर सकते हैं, लेकिन मुझे संदेह है कि एक अंतर है!

इंटरव्यू पहले से कम हो रहे हैं।


2

बस एक तरफ के रूप में (मुझे वास्तव में लगता है कि कोई भी सभ्य संकलक इस प्रश्न को गलत बना देगा, क्योंकि यह इसे अनुकूलित करेगा) 0 == फ्लैग ओवर का उपयोग करके == 0 टाइपो को रोकता है जहां आप किसी एक को भूल जाते हैं (यानी यदि आप गलती से टाइप करते हैं झंडा = 0 यह संकलित करेगा, लेकिन 0 = झंडा नहीं होगा), जो मुझे लगता है कि एक गलती है जो हर किसी ने एक बिंदु या किसी अन्य पर बनाई है ...


0

यदि सभी में अंतर था, तो एक बार तेजी का चयन करने के लिए संकलक क्या रोकता है? इसलिए तार्किक रूप से, कोई अंतर नहीं हो सकता। संभवतः यह साक्षात्कारकर्ता की अपेक्षा है। यह वास्तव में एक शानदार सवाल है।

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