2015-03-07 7 views
17

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

इस

कोड है:

int fib_tail(int n, int res, int next) { 
    if (n == 0) { 
    return res; 
    } 
    return fib_tail(n - 1, next, res + next); 
} 

int main() 
{ 
    fib_tail(10,0,1); //Tail Recursion works 
} 

जब मैं रिलीज मोड का उपयोग कर संकलित मैं एक कॉल के बावजूद जेएमपी अनुदेश का उपयोग कर अनुकूलित विधानसभा देखा। तो मेरा निष्कर्ष था: पूंछ रिकर्सन काम करता है। नीचे चित्र देखें:

Tail Recursion

मैं अपने फाइबोनैचि समारोह में इनपुट चर n में वृद्धि से कुछ प्रदर्शन परीक्षण करना चाहता था। मैंने फिर इंटरफ़ेस से लंबे समय तक हस्ताक्षर किए गए फ़ंक्शन में उपयोग किए गए वेरिएबल प्रकार को बदलने का विकल्प चुना। तब मैं पारित कर दिया की तरह एक बड़ी संख्या: 10e + 08

यह अब नए कार्य है:

typedef unsigned long long ULONG64; 

ULONG64 fib_tail(ULONG64 n, ULONG64 res, ULONG64 next) { 
    if (n == 0) { 
    return res; 
    } 
    return fib_tail(n - 1, next, res + next); 
} 

int main() 
{ 
    fib_tail(10e+9,0,1); //Tail recursion does not work 
} 

जब मैं कोड भाग गया ऊपर मैं एक ढेर अतिप्रवाह अपवाद है, जो मुझे लगता है कि पूंछ प्रत्यावर्तन था मिल गया काम नहीं कर रहा। मैं विधानसभा को देखा और वास्तव में मैं इस पाया:

Tail Recursion doesn't work

जैसा कि आप देख अब वहाँ एक कॉल अनुदेश जबकि मैं केवल एक साधारण जेएमपी उम्मीद कर रहा था है। मैं समझ नहीं पा रहा हूं कि एक 8 बाइट वेरिएबल का उपयोग क्यों पूंछ रिकर्सन अक्षम करता है। क्यों कंपेलर ऐसे मामले में अनुकूलन नहीं करता है?

+0

क्या आप 32-बिट प्लेटफॉर्म को लक्षित कर रहे हैं? –

+0

हां, मैं Win32 – codingadventures

+0

@JohnField को लक्षित कर रहा हूं क्या आप लंबे समय तक फ़ंक्शन के वीएस जेनरेट किए गए डिस्सेप्लर प्रदान कर सकते हैं? – rutsky

उत्तर

8

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

बजना 3.7 यह आंकड़े आउट:

_Z8fib_tailyyy:       # @_Z8fib_tailyyy 
    pushl %ebp 
    pushl %ebx 
    pushl %edi 
    pushl %esi 
    pushl %eax 
    movl 36(%esp), %ecx 
    movl 32(%esp), %esi 
    movl 28(%esp), %edi 
    movl 24(%esp), %ebx 
    movl %ebx, %eax 
    orl %edi, %eax 
    je .LBB0_1 
    movl 44(%esp), %ebp 
    movl 40(%esp), %eax 
    movl %eax, (%esp)   # 4-byte Spill 
.LBB0_3:        # %if.end 
    movl %ebp, %edx 
    movl (%esp), %eax   # 4-byte Reload 
    addl $-1, %ebx 
    adcl $-1, %edi 
    addl %eax, %esi 
    adcl %edx, %ecx 
    movl %ebx, %ebp 
    orl %edi, %ebp 
    movl %esi, (%esp)   # 4-byte Spill 
    movl %ecx, %ebp 
    movl %eax, %esi 
    movl %edx, %ecx 
    jne .LBB0_3 
    jmp .LBB0_4 
.LBB0_1: 
    movl %esi, %eax 
    movl %ecx, %edx 
.LBB0_4:        # %return 
    addl $4, %esp 
    popl %esi 
    popl %edi 
    popl %ebx 
    popl %ebp 
    retl 


main:         # @main 
    subl $28, %esp 
    movl $0, 20(%esp) 
    movl $1, 16(%esp) 
    movl $0, 12(%esp) 
    movl $0, 8(%esp) 
    movl $2, 4(%esp) 
    movl $1410065408, (%esp)  # imm = 0x540BE400 
    calll _Z8fib_tailyyy 
    movl %edx, f+4 
    movl %eax, f 
    xorl %eax, %eax 
    addl $28, %esp 
    retl 

ही जीसीसी के लिए 4.9.2 यदि आप इसे देने के लिए लागू होता है -O2 (लेकिन -O1 जो सभी बजना जरूरी था में नहीं)

(और निश्चित रूप से 64-बिट मोड में भी)

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