【问题标题】:Fibonacci Series in Assembly x86汇编 x86 中的斐波那契数列
【发布时间】:2016-06-05 10:14:59
【问题描述】:

经过漫长的无数次错误,希望这是最后一个。

没有编译或运行时错误,只是逻辑错误。

编辑:(固定伪代码)

我的伪代码:

first  = 1;
second = 1;
third  = 0;

 for i from 1 to n{

    third=first+second
    first=second
    second=third

}
return third

这将打印系列的最终结果。

我的汇编代码:

我尽可能添加评论

.386
.model flat,stdcall
option casemap:none

.data
timestell     db "Loop Ran : %d Times -----",0     ;format string
fmtd   db "%d",0
finalprint  db "Final Number is : %d ------",0     ;format string
times  dd 0Ah                                      ;times to loop
first dd 1h
second dd 1h
third dd 0h


.data?

retvalue1 dd ?             ;we will initialize it later

.code
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
includelib MSVCRT
extrn printf:near
extrn exit:near

public main
main proc


         mov ecx, times      ;loop "times" times
         mov eax,0           ;just to store number of times loop ran
      top:                   ;body of loop
         cmp ecx, 0          ;test at top of loop
         je bottom           ;loop exit when while condition false
         add eax,1           ;Just to test number of times loop ran
         mov ebx,first       ;move first into ebx
         add ebx,second      ;add ebx, [ first+second ]
         mov third,ebx       ;Copy result i.e ebx [first+second] to third
         xor ebx,ebx         ;clear for further use
         mov ebx,first       ;move first into ebx
         mov second,ebx      ;copy ebx to second [NOW second=first]
         xor ebx,ebx         ;clear for later use
         mov ebx,third       ;move thirs into ebx
         mov second,ebx      ;copy ebx to third [NOW second=third]
         xor ebx,ebx         ;clear it
         dec ecx             ;decrement loop
         jmp top             ;Loop again

      bottom:
           mov retvalue1,eax       ;store eax into a variable
           push retvalue1          ;pass this variable to printf
           push offset timestell   ;pass Format string to printf    
           call printf             ;Print no.  of times loop ran
           push third              ;push value of third to printf
           push offset finalprint  ;push the format string
           call printf             ;Print the final number


      push 0        ;exit gracefully
      call exit     ;exit system

main endp

end main

代码运行良好,但输出不让我满意:

输出:Loop Ran : 10 Times -----Final Number is : 11 ------

首先我不确定最终数字是十进制还是十六进制。

  • 假设为十进制:斐波那契数列没有 11
  • 假设它是十六进制:斐波那契数列没有 17(十六进制 11 = 十二月 17)

我做错了什么?

【问题讨论】:

  • 无需不确定打印的数字是否为十进制。 printf 使用finalprint 字符串作为格式,如果它类似于常规的printf,它将使用%d 以十进制形式输出。
  • 只需将您的 cmets 与您真正想做的比较;) NOW second=first 是的,但您想要 first=second ... 哎呀。您可以通过评论获得 +1,这就是我们发现您的错误的方式。
  • 注意:伪代码返回正确的斐波那契数,尽管对于 n=10 它返回 144,技术上是 12th fib num(或 89,取决于如何n 已初始化,但仍差一点)。
  • @Jester 谢谢,我会记住这一点,下次:)
  • @RadLexus 感谢您的信息:)

标签: assembly x86 fibonacci


【解决方案1】:

问题是我的实际代码与导致逻辑错误的伪代码不匹配。

这部分

     mov ebx,first       ;move first into ebx
     mov second,ebx      ;copy ebx to second [NOW second=first]

这使first 的值为second,但我的伪代码显示“first=second”,这意味着将second 的值赋予first

     mov ebx,second      ;move second into ebx
     mov first,ebx       ;copy ebx to second [NOW first=second]

x86 Intel 处理器的最终工作代码:

对于任何进一步的推荐人,我正在发布 x86 英特尔的工作代码

.386
.model flat,stdcall
option casemap:none

.data
timestell   db   "Loop Ran : %d Times -----",0          ;format string
finalprint  db   "%d th Fibonacci number is %d",0       ;format string
times       dd   14h                                    ;times to loop
first dd 1h
second dd 1h
third dd 0h



.code
include windows.inc
include user32.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib
includelib MSVCRT
extrn printf:near
extrn exit:near

public main
main proc


         mov ecx, times       ;set loop counter to "times" time
         sub ecx,2            ;loop times-2 times

      top:
         cmp ecx, 0          ; test at top of loop
         je bottom           ; loop exit when while condition false
         xor ebx,ebx         ;Clear ebx
         mov ebx,first       ;move first into ebx
         add ebx,second      ;add ebx, [ first+second ]
         mov third,ebx       ;Copy result i.e ebx [first+second] to third
         xor ebx,ebx         ;clear for further use
         mov ebx,second      ;move second into ebx
         mov first,ebx       ;copy ebx to second [NOW first=second]
         xor ebx,ebx         ;clear for later use
         mov ebx,third       ;move thirs into ebx
         mov second,ebx      ;copy ebx to third [NOW second=third]
         xor ebx,ebx         ;clear it
         dec ecx             ;decrement loop
         jmp top             ;Loop again

      bottom:
        push third
              push times                ;push value of third to printf
              push offset finalprint    ;push the format string
              call printf               ;Print the final number
      push 0        ;exit gracefully
         call exit      ;exit system

    main endp

end main

【讨论】:

  • 作为一般注释,将值存储在寄存器中的代码总是比将值存储在内存中的类似代码更简单、更短和更快,尽管需要做更多的工作来注释哪个变量在哪个注册。你可以在这里轻松地做到这一点。您学到的另一个教训是,在致力于编写汇编代码之前,通常值得用更高级的语言对算法进行实际编码(而不是伪编码)。在 HLL 中看到错误比在汇编中看到同样的错误要容易得多。
  • @Gene 对不起,我是组装的新手,因为它有所不同。我没明白你说什么。您的意思是说我还应该评论哪个变量在哪个寄存器中?喜欢而不是;move second into ebx 我应该写ebx=second ?我首先在 Javascript 中测试了伪代码,我似乎错过了错误,因为我的代码给出了正确的数字,但比请求的第 n 个数字提前了两步,我专注于简单性,这让我错过了这个小错误。
  • 你做得很好。不,我是说您根本不需要内存位置。例如。对第一、第二和第三使用 esi、edi 和 edx。这仍然留下 3 个寄存器用于循环计数、临时值等。
  • @PeterCordes @Gene 现在我明白了,你的意思是说我根本不需要使用firstsecondthird 变量,我可以假设寄存器eax ,ebx,edx 作为对应的变量。这将节省内存并提高效率。如果我错了,请纠正我。谢谢
  • 查看非常短的 C 函数的优化编译器输出是学习一些技巧的好方法。 gcc.godbolt.org 非常适合:我一直使用它在我的答案中发布 asm 链接。编写接受 args 并返回值或存储到全局的函数,这样它们就不会被优化掉。
猜你喜欢
  • 2021-07-18
  • 2019-07-11
  • 2013-01-25
  • 2012-03-25
  • 2011-08-02
  • 2012-11-06
  • 2013-10-13
  • 2014-06-24
  • 1970-01-01
相关资源
最近更新 更多