2010-04-15 7 views
5

मैंने अभी इस कार्य को असाइनमेंट में सौंप दिया है। यह किया जाता है (इसलिए कोई होमवर्क टैग नहीं)। लेकिन मैं देखना चाहता हूं कि यह कैसे सुधार किया जा सकता है।एक साधारण असेंबली फ़ंक्शन को सुधारने में सहायता

अनिवार्य रूप से, समारोह 1 के बीच सभी पूर्णांकों और दिए गए नंबर के वर्गों का योग, निम्न सूत्र का उपयोग कर:

n(n+1)(2n+1)/6 

कहाँ n अधिकतम संख्या है।

नीचे दिया गया कार्य किसी भी अतिप्रवाह को पकड़ने के लिए बनाया गया है और 0 को किसी भी घटना को वापस करना चाहिए।

UInt32 sumSquares(const UInt32 number) 
{ 
    int result = 0; 
    __asm 
    { 
     mov eax, number //move number in eax 
     mov edx, 2  //move 2 in edx 
     mul edx   //multiply (2n) 
     jo end   //jump to end if overflow 
     add eax, 1  //addition (2n+1) 
     jo end   //jump to end if overflow 
     mov ecx, eax  //move (2n+1) in ecx 

     mov ebx, number //move number in ebx 
     add ebx, 1  //addition (n+1) 
     jo end   //jump to end if overflow 

     mov eax, number //move number in eax for multiplication 
     mul ebx   //multiply n(n+1) 
     jo end   //jump to end if overflow 
     mul ecx   //multiply n(n+1)(2n+1) 
     jo end   //jump to end if overflow 
     mov ebx, 6  //move 6 in ebx 
     div ebx   //divide by 6, the result will be in eax 

     mov result, eax //move eax in result 

end: 
    } 

    return result; 
} 

असल में, मैं पता है कि मैं वहाँ में सुधार कर सकते हैं चाहता हूँ। अधिकतर सर्वोत्तम प्रथाओं के संदर्भ में। एक बात स्पष्ट दिखाई देती है: स्मार्ट ओवरफ्लो चेक (जो भी अधिकतम इनपुट के लिए एक चेक के साथ एक ओवरफ्लो का कारण बनता है)।

+1

CodeReview अभी तक बीटा से बाहर नहीं है, लेकिन यह एक अच्छा उम्मीदवार हो सकता है एक बार यह है। –

उत्तर

8
mov eax, number //move number in eax 
    mov ecx, eax  //dup in ecx 
    mul ecx   //multiply (n*n) 
    jo end   //jump to end if overflow 
    add eax, ecx  //addition (n*n+n); can't overflow 
    add ecx, ecx  //addition (2n); can't overflow 
    add ecx, 1  //addition (2n+1); can't overflow 
    mul ecx   //multiply (n*n+n)(2n+1) 
    jo end   //jump to end if overflow 
    mov ecx, 6  //move 6 in ebx 
    div ecx   //divide by 6, the result will be in eax 

    mov result, eax //move eax in result 

शक्ति में कमी: गुणा करने के बजाय जोड़ें।

विश्लेषण करके, कम ओवरफ़्लो चेक (जैसा कि आपने वर्णन किया है उतना बेहतर कर सकते हैं)।

स्टैक पर तर्क पर वापस जाने के बजाय रजिस्टरों में मान रखें।

चुस सावधानी से पंजीकृत करता है ताकि मूल्यों का पुन: उपयोग किया जा सके जिन्हें ओवरराइट नहीं किया जा सकता है।

+0

जोड़ें अतिप्रवाह नहीं कर सकते हैं? क्या मेरे द्वारा इसे सही से पढ़ा जा रहा है? – MPelletier

+3

अतिप्रवाह नहीं हो सकता क्योंकि एन * एन नहीं था, इसलिए एन * एन + एन नहीं होगा। सबसे बड़ा एन जैसे कि एन * एन ओवरफ्लो नहीं होगा 0xffff है। 0xffff * 0xffff + 0xffff = 0xffff0000। चूंकि उस बिंदु पर n <= 0xffff, 2n + 1 अधिकतर 0x1ffff पर है, फिर से कोई ओवरफ़्लो नहीं है। –

+0

अगर मैं कर सकता तो मैं आपको दो बार वोट दूंगा। यह ठोस गणित है! – MPelletier

3
mov eax, number ; = n 
cmp eax, 0x928  ; cannot handle n >= 0x928 
jnc end 
shl eax, 1   ; = n(2) 
add eax, 3   ; = n(2)+3 
mov ebx, number 
mul ebx   ; = n(n(2)+3) 
add eax, 1   ; = n(n(2)+3)+1 
mov ebx, number 
mul ebx   ; = n(n(n(2)+3)+1) = n(n+1)(2n+1) 
mov ebx, 6 
div ebx 
mov result, eax 

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

3
UInt32 sumSquares(const UInt32 number) 
{ 
    __asm 
    { 
    mov eax, number  // n 
    cmd eax, MAX_VALUE 
    jg bad_value 

    lea ebx, [eax+1] // n + 1 
    lea ecx, [2*eax+1] // 2n + 1 

    mul ebx 
    mul ecx 

    shr eax, 1   // divide by 2 
    mov ebx, 2863311531 // inverse of 3 
    mul ebx    // divide by 3 

    ret 

    bad_value: 
    xor eax, eax  // return 0 
    ret 
    } 
} 

http://blogs.msdn.com/devdev/archive/2005/12/12/502980.aspx

Spara

+0

ली चाल के बारे में बात करना दिलचस्प है; मेरा मानना ​​है कि वे नए प्रोसेसर पर सीधा अंकगणित से धीमे हो सकते हैं। उलटा गुणा एक अच्छी तकनीक है कि मेरे पास कल वर्णन करने की ऊर्जा नहीं थी; मुझे लगता है कि आपका परिणाम edx में है, हालांकि, आपको इसे eax पर ले जाने की आवश्यकता है। –

+0

@Doug Currie मुझे यकीन नहीं है कि आपको क्या लगता है कि परिणाम EDX में है। सभी ऑपरेशन ईएक्स पर किए जाते हैं और गुणा के उच्च ऑर्डर बिट्स ईडीएक्स (जिन्हें छोड़ दिया जाता है) में होते हैं। क्या मैं कुछ भूल रहा हूँ? दिलचस्प अंकगणितीय चाल निश्चित रूप से संभव हैं, लेकिन आपने पहले इसका अच्छा काम किया था इसलिए मैंने अधिक सीधा-आगे उदाहरण चुना। – Sparafusile

+0

मैंने अनुमान लगाया कि आप 1431655765 (2^32/3) से गुणा कर रहे थे। करीब पढ़ना मुझे लगता है कि आप नहीं हैं। उलटा गुणा करके आप केवल तभी काम करते हैं जब लाभांश विभाजक का सटीक बहु होता है। आश्चर्यजनक रूप से यह इस एल्गोरिदम के लिए मामला है। +1 –

संबंधित मुद्दे