2012-10-02 24 views
44

जब मैं कुलपति ++ 10 के साथ इस कोड संकलन:ऐसे जटिल कोड को दो की शक्ति द्वारा हस्ताक्षरित पूर्णांक को विभाजित करने के लिए क्यों उत्सर्जित किया जाता है?

DWORD ran = rand(); 
return ran/4096; 

मैं इस disassembly मिलती है:

299: { 
300: DWORD ran = rand(); 
    00403940 call  dword ptr [__imp__rand (4050C0h)] 
301: return ran/4096; 
    00403946 shr   eax,0Ch 
302: } 
    00403949 ret 

जो स्वच्छ और संक्षिप्त है और एक तार्किक अधिकार के साथ दो का एक शक्ति से एक प्रभाग की जगह खिसक जाना।

फिर भी जब मैं इस कोड संकलन:

299: { 
300: int ran = rand(); 
    00403940 call  dword ptr [__imp__rand (4050C0h)] 
301: return ran/4096; 
    00403946 cdq 
    00403947 and   edx,0FFFh 
    0040394D add   eax,edx 
    0040394F sar   eax,0Ch 
302: } 
    00403952 ret 

है कि एक सही गणित बदलाव करने से पहले कुछ जोड़तोड़ करती है:

int ran = rand(); 
return ran/4096; 

मैं इस disassembly मिलता है।

उन अतिरिक्त कुशलताओं की क्या आवश्यकता है? एक अंकगणित शिफ्ट पर्याप्त क्यों नहीं है?

+3

एफडब्ल्यूआईडब्ल्यू, सी 8 9 और सी ++ 03 में यह क्रियान्वयन-परिभाषित किया गया था जिस तरह से नकारात्मक ऑपरेटरों के लिए पूर्णांक विभाजन दौर। सी 99 और सी ++ 11 में यह नहीं है। –

+2

उसके लिए इतने सारे अपवॉट्स? –

+0

@AlexeyFrunze यह वास्तव में बहुत अधिक चीजों की तुलना में बहुत अच्छा है जो व्यापक रूप से ऊपर उठाया जाता है। तो मैं इसे अवांछित के रूप में नहीं देखता हूं। – Mysticial

उत्तर

90

कारण यह है कि 2^एन द्वारा हस्ताक्षरित विभाजन को बहुत सरलता से कार्यान्वित किया जा सकता है, जबकि हस्ताक्षरित विभाजन कुछ और जटिल है।

unsigned int u; 
int v; 

u/4096u के सभी संभव मूल्यों के लिए u >> 12 के बराबर है।

v/4096नहीं बराबर v >> 12 लिए है - यह जब v < 0 टूट जाती है, गोलाई दिशा के रूप में विभाजन बनाम स्थानांतरण जब नकारात्मक संख्या शामिल कर रहे हैं के लिए अलग है।

+5

+1। – WhozCraig

+0

@Vlad: मेरा मानना ​​है कि 'int' * * हमेशा डिफ़ॉल्ट रूप से हस्ताक्षरित है - शायद आप' char' के बारे में सोच रहे हैं? –

+0

@ पॉल आर: ओह, वास्तव में, बुरे द्वारा, धन्यवाद! – Vlad

34

"अतिरिक्त कुशलता" इस तथ्य की भरपाई करता है कि अंकगणित दाएं-शिफ्ट नकारात्मक अनंतता की ओर परिणाम को गोल करता है, जबकि विभाजन शून्य की ओर परिणाम को गोल करता है।

उदाहरण के लिए, -1 >> 1-1 है, जबकि -1/20 है।

10

सी मानक से:

जब पूर्णांक विभाजित हैं,/ऑपरेटर का परिणाम किसी भी आंशिक हिस्सा discarded.105 साथ बीजीय भागफल है) यदि भागफल a/b प्रदर्शनीय, है अभिव्यक्ति (ए/बी) * बी + एक% बी बराबर होगा; अन्यथा, ए/बी और% बी दोनों का व्यवहार अपरिभाषित है।

उदाहरणों के बारे में सोचना मुश्किल नहीं है जहां नकारात्मक नियमों को शुद्ध अंकगणितीय शिफ्ट के साथ इस नियम का पालन नहीं किया जाता है। जैसे

(-8191)/4096 -> -1 
(-8191) % 4096 -> -4095 

जो समीकरण को संतुष्ट करता है, जबकि

(-8191) >> 12 -> -2 (assuming arithmetic shifting) 

काट-छांट के साथ विभाजन नहीं है, और इसलिए -2 * 4096 - 4095 सबसे निश्चित रूप से -8191 के बराबर नहीं है।

ध्यान दें कि नकारात्मक संख्याओं को स्थानांतरित करना वास्तव में कार्यान्वयन-परिभाषित है, इसलिए सी अभिव्यक्ति (-8191) >> 12 मानक के अनुसार आमतौर पर सही परिणाम नहीं है।