assembly 如何计算从0到1x10^6之间的斐波那契数的奇数和

oymdgrw7  于 2023-04-12  发布在  其他
关注(0)|答案(1)|浏览(80)

我在创建一个x64 masm程序来计算奇数值之和的结果时遇到了麻烦。答案在RAX中为109E82h(1089154d).我正在努力弄清楚masm是如何工作的,但它是如此令人困惑,这是我到目前为止尝试过的,但RAX寄存器中的值不正确,我已经尽我所能尝试过了,但我不知道我错在哪里。

extrn ExitProcess: proc

.data
fib1 QWORD 0
fib2 QWORD 1
sum QWORD 0
  
.code
_main PROC

    ; calculate the Fibonacci sequence up to 10^7
    mov rax, 10000000
    mov rcx, fib1
    mov rdx, fib2
FIB_LOOP:
    add rcx, rdx
    mov fib1, rdx
    mov fib2, rcx
    cmp rcx, rax
    jle FIB_LOOP
    ; add odd numbers to the sum
    mov rcx, fib1
    add rcx, rdx  ; rdx contains the last even Fibonacci number
SUM_LOOP:
    test cl, 1    ; check if the current number is odd
    jz SKIP_ADD
    add sum, rcx
SKIP_ADD:
    add rcx, rdx
    mov rdx, rcx
    cmp rcx, rax
    jle SUM_LOOP

    ; exit the program
    mov rax, sum
    call ExitProcess

_main ENDP
END
sulc1iza

sulc1iza1#

但我不知道我错在哪里。
好吧,我不明白为什么你的程序的第一部分是计算斐波那契数列直到10^7,当标题提到你需要处理[0,10 ^6]范围内的数字时。这比需要的高10倍!在那之后,求和循环进入更大的数字,幸运的是RAX限制没有改变,所以这部分很快就退出了。

  • 在运行创建奇数斐波那契数的循环时,需要对奇数斐波那契数求和。
  • 在这段代码中,你可以避免使用基于内存的变量,因为你有很多寄存器可以使用。
  • 虽然你想要64位代码,但你并不总是需要使用64位寄存器。任务的有限数值范围允许你使用更有效的32位寄存器。由于写入64位寄存器的低dword会自动将高dword置零,因此最终RAX将保存结果1089154。
xor  eax, eax     ; RAX=0 is Number1 (Fibonacci)
  lea  ecx, [rax+1] ; RCX=1 is Number2
  cdq               ; RDX=0 is SumOfOdds

More:
  xchg eax, ecx     ; -> RCX = 0,  1,  1,  2,  3,  5,   8, ...
  add  eax, ecx     ; -> RAX = 1,  1,  2,  3,  5,  8,  13, ...
  test al, 1
  jz   isEven
  add  edx, eax     ; -> RDX  +1, +1,     +3, +5,     +13, ...
isEven:
  cmp  eax, 1000000
  jb   More

  test al, 1        ; Keep this one-time correction outside of the loop
  jz   Done
  sub  edx, eax     ; Take back last addition of an odd Fib
Done:
  xchg eax, edx     ; Final result in RAX

这可能是一个有趣的替代方案(未经测试):

xor  eax, eax     ; RAX=0 is SumOfOdds
  lea  ecx, [rax+1] ; RCX=1 is Number2
  cdq               ; RDX=0 is Number1 (Fibonacci)

SumIt:
  add  eax, edx     ; -> RAX  +1, +1,     +3, +5,     +13, ...
More:
  xchg edx, ecx     ; -> RCX = 0,  1,  1,  2,  3,  5,   8, ...
  add  edx, ecx     ; -> RDX = 1,  1,  2,  3,  5,  8,  13, ...
  test dl, 1
  jz   More
  cmp  edx, 1000000
  jb   SumIt

                    ; Final result in RAX

相关问题