this answer पर एक टिप्पणी में (जो प्रदर्शन के लिए पूर्णांक गुणा/विभाजन पर बिट-शिफ्ट ऑपरेटरों का उपयोग करने का सुझाव देता है), मैंने पूछा कि यह वास्तव में तेज़ होगा या नहीं। मेरे दिमाग के पीछे एक विचार है कि पर कुछ स्तर पर, कुछ >> 1
और / 2
काम करने के लिए पर्याप्त चालाक होगा। हालांकि, अब मैं सोच रहा हूं कि यह वास्तव में सच है, और यदि यह है, तो यह किस स्तर पर होता है।क्या सीआई/सीआईएल के लिए जेआईटीटर द्वारा उत्पादित मूल कोड देखने का कोई तरीका है?
IL_0000: ldarg.0
IL_0001: ldc.i4.2
IL_0002: div
IL_0003: ret
} // end of method Program::Divider
बनाम
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: shr
IL_0003: ret
} // end of method Program::Shifter
तो सी # संकलक div
उत्सर्जित करती है:
एक परीक्षण कार्यक्रम दो तरीकों कि क्रमशः विभाजित और उनके तर्क बदलाव के लिए (पर optimize
के साथ) में निम्न तुलनात्मक सीआईएल का उत्पादन या shr
निर्देश, चतुर होने के बिना। अब मैं वास्तविक x86 असेंबलर देखना चाहता हूं जो कि जिटर उत्पन्न करता है, लेकिन मुझे नहीं पता कि यह कैसे करना है। क्या यह भी संभव है?
संपादित जवाब के लिए
निष्कर्ष
धन्यवाद जोड़ने के लिए है, क्योंकि यह है कि डीबगर विकल्प के बारे में महत्वपूर्ण जानकारी निहित nobugz से एक स्वीकार कर लिया है। क्या अंत में मेरे लिए काम किया है:
- स्विच विन्यास
- रिलीज करने
Tools | Options | Debugger
में, बंद 'मॉड्यूल लोड पर JIT अनुकूलन को रोकें' (यानी हम चाहते हैं कि JIT अनुकूलन की अनुमति) - एक ही जगह है, बंद 'बस मेरे कोड सक्षम'
- एक
Debugger.Break()
बयान रखो कहीं - विधानसभा का निर्माण (यानी हम डिबग करने के लिए सभी कोड चाहते हैं)
- .exe चलाएँ, और जब यह टूट जाता है, उदाहरण के वी.एस. मौजूदा का उपयोग कर डिबग
- अब Disassembly खिड़की आप वास्तविक x86 कि निष्पादित किया जाना है
परिणाम कम से कम कहने के लिए शिक्षाप्रद थे जा रहा है पता चलता - यह पता चला कि जिटर वास्तव में अंकगणित कर सकता है! Disassembly विंडो से संपादित नमूने यहां दिए गए हैं। विभिन्न -Shifter
विधियों को >>
का उपयोग करके दो की शक्तियों से विभाजित किया गया है; विभिन्न -Divider
तरीकों /
Console.WriteLine(string.Format("
{0}
shift-divided by 2: {1}
divide-divided by 2: {2}",
60, TwoShifter(60), TwoDivider(60)));
00000026 mov dword ptr [edx+4],3Ch
...
0000003b mov dword ptr [edx+4],1Eh
...
00000057 mov dword ptr [esi+4],1Eh
दोनों स्थिर-विभाजित-दर-2 तरीकों केवल inlined नहीं किया गया है का उपयोग कर पूर्णांकों से विभाजित है, लेकिन वास्तविक संगणना घबराना
Console.WriteLine(string.Format("
{0}
divide-divided by 3: {1}",
60, ThreeDivider(60)));
00000085 mov dword ptr [esi+4],3Ch
...
000000a0 mov dword ptr [esi+4],14h
के साथ भी यही द्वारा किया गया हो स्थिर-विभाजित-दर-3।
Console.WriteLine(string.Format("
{0}
shift-divided by 4: {1}
divide-divided by 4 {2}",
60, FourShifter(60), FourDivider(60)));
000000ce mov dword ptr [esi+4],3Ch
...
000000e3 mov dword ptr [edx+4],0Fh
...
000000ff mov dword ptr [esi+4],0Fh
और स्थैतिक रूप से विभाजित -4 -4।
सबसे अच्छा:
Console.WriteLine(string.Format("
{0}
n-divided by 2: {1}
n-divided by 3: {2}
n-divided by 4: {3}",
60, Divider(60, 2), Divider(60, 3), Divider(60, 4)));
0000013e mov dword ptr [esi+4],3Ch
...
0000015b mov dword ptr [esi+4],1Eh
...
0000017b mov dword ptr [esi+4],14h
...
0000019b mov dword ptr [edi+4],0Fh
यह inlined है और फिर इन सभी स्थिर डिवीजनों अभिकलन!
लेकिन यदि परिणाम स्थिर नहीं है तो क्या होगा? मैंने कंसोल से एक पूर्णांक पढ़ने के लिए कोड में जोड़ा। यह वही है कि पर डिवीजनों के लिए उत्पादन होता है:
Console.WriteLine(string.Format("
{0}
shift-divided by 2: {1}
divide-divided by 2: {2}",
i, TwoShifter(i), TwoDivider(i)));
00000211 sar eax,1
...
00000230 sar eax,1
तो के बावजूद कोल इंडिया अलग किया जा रहा है, घबराना कोई जानता है कि 2 से विभाजित राइट स्थानांतरण 1.
Console.WriteLine(string.Format("
{0}
divide-divided by 3: {1}", i, ThreeDivider(i)));
00000283 idiv eax के द्वारा होता है, ECX
और यह जानता है कि आप द्वारा 3.
Console.WriteLine(string.Format("
{0}
shift-divided by 4: {1}
divide-divided by 4 {2}",
i, FourShifter(i), FourDivider(i)));
000002c5 sar eax,2
...
000002ec sar eax,2
विभाजित करने के लिए विभाजित करने के लिए है और यह kno ws 4 से कि विभाजन सही-स्थानांतरण द्वारा 2.
अंत में(सबसे अच्छा फिर से!) है
Console.WriteLine(string.Format("
{0}
n-divided by 2: {1}
n-divided by 3: {2}
n-divided by 4: {3}",
i, Divider(i, 2), Divider(i, 3), Divider(i, 4)));
00000345 sar eax,1
...
00000370 idiv eax,ecx
...
00000395 sar esi,2
यह विधि inlined और सबसे अच्छा तरीका है काम करने के लिए बाहर काम किया है, statically- के आधार पर उपलब्ध तर्क। अच्छा लगा।
तो हाँ, C# और 86 के बीच ढेर में कहीं, कुछ पर्याप्त चतुर बाहर काम करने कि >> 1
और / 2
समान हैं। और इसने मेरे दिमाग में मेरे विचार में और भी अधिक वजन दिया है कि सी # कंपाइलर, जेआईटर और सीएलआर को जोड़कर एक बहुत छोटी चाल से हम आर बनाते हैं, हम विनम्र अनुप्रयोग प्रोग्रामर के रूप में कोशिश कर सकते हैं :)
क्या आप हमारे निष्कर्षों को हम सभी के लिए पोस्ट कर सकते हैं? धन्यवाद :) – flesh