Windows汇编语言程序设计同步练习(2)

时间:2021-12-17 04:51:13

;《Windows汇编语言程序设计教程》p170习题7:
;用递归子程序显示Fibonacci数列,Fibonacci数列Fn定义为:F0=0,F1=1,F2=1,Fn=Fn-2+Fn-3(n>=3)。
;2006-12-15 高玉涵
;程序不考虑处理负数与溢出。
.386
.model flat,stdcall
option casemap:none
includelib  /masm32/lib/msvcrt.lib
printf      PROTO C :dword, :vararg
scanf       PROTO C :dword, :vararg

.data
dVar        dword   6                      
szMsg1      byte    '请输入一个大于2的整数:', 0
szMsg3      byte    'F%d = %d', 0ah, 0
szMsg4      byte    'ebx=%d', 0ah, 0
szInputFmt  byte    '%d', 0

.code
Fibonacci   proc C n:dword
            local dret:dword        ;存放子程序的返回值。
            local dvar:dword        ;存放n值(中间计算)。
            cmp n, 2
            jle exitrecurse         ;n<=2

            push n
            pop dvar                ;dvar=n
            dec dvar                ;n-1
            invoke Fibonacci, dvar  ;Fibonacci(n-1)
            mov dret, eax           ;保存上次调用的返回值。
            dec dvar                ;相当于n-2
            invoke Fibonacci, dvar  ;Fibonacci(n-2)
            add eax, dret           ;eax子程序返回值,eax=n-1+n-2。
            ret   
              
exitrecurse:
            mov eax, 1          ;保存子程序返回值。
            ret  
              
Fibonacci   endp

start       proc
            invoke  printf, offset szMsg1                   ;提示。
            invoke  scanf, offset szInputFmt, offset dVar   ;获取用户输入的值。

            cmp dVar, 2
            jle exitrecurse                                 ;dVar<=2,退出。
           
            mov ecx, dVar
    lop:
            push ecx                                        ;保存ecx值。
            invoke  Fibonacci, ecx
            invoke  printf, offset szMsg3, ecx, eax
            pop ecx                                         ;还原ecx值。
            loop lop

exitrecurse:
            ret
           
start       endp
end         start 

程序运行结果:
请输入一个大于2的整数:7
F7 = 13
F6 = 8
F5 = 5
F4 = 3
F3 = 2
F2 = 1
F1 = 1

注:
     程序中有一个陷阱:它使用递归步骤计算Fibonacci(n-1)和Fibonacci(n-2),但是,在计算Fibonacci(n-1)时也将计算Fibonacci(n-2),这个额外的计算代价有多大呢?
     答案是:它的代价远远不止一个冗余计算:每个递归调用都触发另外两个递归调用,而这两个调用的任何一个还将触发两个递归调用,再接下去的调用也是如此。这样,冗余计算数量增长得非常快。例如:在递归计算Fibonacci(10)时,Fibonacci(3)的值被计算了21次。但是,在递归计算Fibonacci(30)时,Fibonacci(3)的值被计算了317,811次。当然,这317,811次计算所产生的结果是完全一样的,除了其中之一外,其余的纯属浪费。这个额外的开销真是相当恐怖!

      以上原句摘自《C和指针》(人民邮电出版社-Kenneth A.Reek著 除波 译)p133页。