我刚刚开始使用 Assembly (NASM),我尝试创建一个变体来解决 Project Euler 问题 1(将 1000 以下的 3 或 5 的所有倍数相加)。我尝试制定算法的变体利用了倍数以重复模式间隔的事实(+3、+2、+1、+3、+1、+2、+3 和重复),但是循环在第一次迭代后退出。
原理应该和这个C解一样,计算出正确的结果:
int sum = 0, s = 0;
int steps[7] = {3,2,1,3,1,2,3};
for (int n = steps[s]; n < 1000; n += steps[s]) {
sum += n;
s++;
if (s == 7)
s = 0;
}
我的汇编看起来像这样:
section .data
msg db "%d", 10, 0 ;return string for printf (just the result)
steps dd 3, 2, 1, 3, 1, 2, 3 ;how the multiples of 3 and 5 are spaced
section .text
extern printf
global main
main:
xor rax, rax ;prepare rax which will store the result
xor rbx, rbx ;prepare rbx, which will be the current number
arr0:
xor rcx, rcx ;prepare rcx, which will be the array index
countup:
add rbx, [steps + rcx * 4] ;add steps@rcx to rbx
add rax, rbx ;add rbx to the result
inc rcx ;increase the array index
cmp rcx, 7 ;check if we reached the end of the array
je arr0 ;if yes, jump to arr0
cmp rbx, 1000 ;check if we reached 1000
jl countup ;if not, loop again
... print and exit come next
程序编译得很好,但结果只有 3,所以显然循环不会重复,只执行一次。为了使其正常工作,我需要改变什么?
如果我手动创建如下所示的重复模式,它工作正常,显然直到我到达数组的末尾。
add rbx, [steps + rcx * 4] ;add steps@rcx to rbx
add rax, rbx ;add rbx to the result
inc rcx ;increase the array index
add rbx, [steps + rcx * 4] ;add steps@rcx to rbx
add rax, rbx ;add rbx to the result
inc rcx ;increase the array index
add rbx, [steps + rcx * 4] ;add steps@rcx to rbx
add rax, rbx ;add rbx to the result
inc rcx ;increase the array index
...
感谢您的评论,我能够解决问题。正如 Erik 所指出的,主要问题是 32/64 位混合。一旦我将所有内容更改为仅使用 eXX 寄存器,或者将数组的数据类型调整为 dq 并将索引的乘数调整为 8,它就完美地工作了。
ecm 当然也是对的,所以我稍微调整了检查和结构:
section .data
msg db "%d", 10, 0 ;return string for printf (just the result)
steps dd 3, 2, 1, 3, 1, 2, 3 ;how the multiples of 3 and 5 are spaced
section .text
extern printf
global main
main:
xor eax, eax ;result
xor ebx, ebx ;current number
xor ecx, ecx ;array index
arr0:
cmp ecx, 7 ;check if we reached the end of the array
jl countup ;if not, continue counting
xor ecx, ecx ;else reset counter
countup:
add eax, ebx ;add current number to result
add ebx, [steps + ecx * 4] ;add steps@ecx to current number
inc ecx ;increase the array index
cmp ebx, 1000 ;check if we reached 1000
jl arr0 ;if not, continue