如何修复 nasm 程序集中斐波那契数列的溢出问题?
How to fix overflow for fibonacci sequence in nasm assembly?
我是一名业余爱好者,我的一项任务是根据我的用户输入来计算斐波那契数列。所以如果我的用户输入是 5,输出将是这样的
0
1个
1个
2个
3个
它被放置在一个数组中,然后索引增加并进行一些算术运算以获得序列。用户输入限制为 25,所以如果用户输入是 25,我的输出应该像上面那样,一直到 46368 的值。起初,我使用 al、bl 和 cl 来做算术运算,但意识到 8 位寄存器太小,我改为 16 位。
在某些时候,这个数字是负数,我知道它是这样的,因为符号位和数字是一个带符号的数字
我如何使所有内容都未签名?
在某种程度上我已经尝试过 PRINT_UDEC 但在某个时间点这个数字又回到了一个小数字并且不会继续加起来
当我编写另一个程序时,我实际上发生了同样的事情,我使用了 al,这是一个 8 位寄存器,所以我只是将它更改为 16 位寄存器并且它起作用了
我也尝试将其更改为 32 位寄存器,但它仍然不起作用!
据我所知(如果我错了请纠正我)ax 的最大值可以达到 65536?
而斐波那契数列的第 25 个数是 46368,这仍然在 16 位寄存器的范围内。
我该如何解决这个溢出问题?
%include "io.inc"
section .bss
fibo resb 26 * 4; reserve an array of 25 uninitialized bytes
userInput resb 4 ; reserve 4 bytes for userInput
section .text
global _main
_main:
mov ebp, esp ; entry point for correct debugging
xor edx, edx ; initializing my secondary index to 0
mov eax, 0 ; a = 0
mov ebx, 1 ; b = 1
mov ecx, 0 ; c = 0
PRINT_STRING "Enter a number between 3 and 25 inclusively:" ;prompt user for integer input
NEWLINE
GET_DEC 4, userInput ;
mov edi, userInput ;
mov esi, fibo ;
call indexInc ;
mov edx, 0 ;
call printarray ;
indexInc:
mov [esi], eax ; moves the a = 0 in the first element of the array
inc esi ; increases array index
mov [esi], ebx ; moves the b = 1 in the second element of the array
inc esi ; increases array index
mov edx, 3 ; secondary pointer for comparison purposes
forloop:
cmp edx, [userInput] ;
jg term ;
add ecx, eax ;
add ecx, ebx ;
mov [esi], ecx ;
mov eax, ebx ;
mov ebx, ecx ;
xor ecx, ecx ;
inc esi ; increase array index
inc edx ; increase secondary pointer
jmp forloop ;
printarray:
cmp edx, [userInput] ;
je term ;
PRINT_DEC 1, [fibo + edx] ;
NEWLINE
inc esi ; increase array index
inc edx ; increase pointer
jmp printarray ;
term:
ret ; terminate program
尝试使用 PRINT_DEC 4, [fibo + edx]
或 PRINT_UDEC 4, [fibo + edx]
。
从 this source.
来看
请注意,装配线不必以 ;
结束 - 这是评论的开始。
此外,您的程序流程和编码风格很混乱:除非您正在打高尔夫球或利用一些技巧,否则不要跨函数共享 ret
。
向前跳 比向后跳 更难理解 - 如果可能的话更喜欢 do {} while ();
而不是 while () {}
.
为标签赋予有意义的名称,并在需要时采用使函数标签脱颖而出的命名约定。
您的评论是商品。
我发现如果汇编代码(一般代码)在空间上分组在逻辑块中会更容易理解 - 避免文本墙效应。
您以两种不同的方式 - 这充其量是奇怪的(最坏的情况是可疑的)。
我认为您只需两条指令即可执行斐波那契步骤:
xchg eax, ebx
add ebx, eax
如果 eax
是 f(n-1)
并且 ebx
是 f(n)
我是一名业余爱好者,我的一项任务是根据我的用户输入来计算斐波那契数列。所以如果我的用户输入是 5,输出将是这样的 0 1个 1个 2个 3个 它被放置在一个数组中,然后索引增加并进行一些算术运算以获得序列。用户输入限制为 25,所以如果用户输入是 25,我的输出应该像上面那样,一直到 46368 的值。起初,我使用 al、bl 和 cl 来做算术运算,但意识到 8 位寄存器太小,我改为 16 位。
在某些时候,这个数字是负数,我知道它是这样的,因为符号位和数字是一个带符号的数字 我如何使所有内容都未签名? 在某种程度上我已经尝试过 PRINT_UDEC 但在某个时间点这个数字又回到了一个小数字并且不会继续加起来 当我编写另一个程序时,我实际上发生了同样的事情,我使用了 al,这是一个 8 位寄存器,所以我只是将它更改为 16 位寄存器并且它起作用了 我也尝试将其更改为 32 位寄存器,但它仍然不起作用! 据我所知(如果我错了请纠正我)ax 的最大值可以达到 65536? 而斐波那契数列的第 25 个数是 46368,这仍然在 16 位寄存器的范围内。 我该如何解决这个溢出问题?
%include "io.inc"
section .bss
fibo resb 26 * 4; reserve an array of 25 uninitialized bytes
userInput resb 4 ; reserve 4 bytes for userInput
section .text
global _main
_main:
mov ebp, esp ; entry point for correct debugging
xor edx, edx ; initializing my secondary index to 0
mov eax, 0 ; a = 0
mov ebx, 1 ; b = 1
mov ecx, 0 ; c = 0
PRINT_STRING "Enter a number between 3 and 25 inclusively:" ;prompt user for integer input
NEWLINE
GET_DEC 4, userInput ;
mov edi, userInput ;
mov esi, fibo ;
call indexInc ;
mov edx, 0 ;
call printarray ;
indexInc:
mov [esi], eax ; moves the a = 0 in the first element of the array
inc esi ; increases array index
mov [esi], ebx ; moves the b = 1 in the second element of the array
inc esi ; increases array index
mov edx, 3 ; secondary pointer for comparison purposes
forloop:
cmp edx, [userInput] ;
jg term ;
add ecx, eax ;
add ecx, ebx ;
mov [esi], ecx ;
mov eax, ebx ;
mov ebx, ecx ;
xor ecx, ecx ;
inc esi ; increase array index
inc edx ; increase secondary pointer
jmp forloop ;
printarray:
cmp edx, [userInput] ;
je term ;
PRINT_DEC 1, [fibo + edx] ;
NEWLINE
inc esi ; increase array index
inc edx ; increase pointer
jmp printarray ;
term:
ret ; terminate program
尝试使用 PRINT_DEC 4, [fibo + edx]
或 PRINT_UDEC 4, [fibo + edx]
。
从 this source.
请注意,装配线不必以 ;
结束 - 这是评论的开始。
此外,您的程序流程和编码风格很混乱:除非您正在打高尔夫球或利用一些技巧,否则不要跨函数共享 ret
。
向前跳 比向后跳 更难理解 - 如果可能的话更喜欢 do {} while ();
而不是 while () {}
.
为标签赋予有意义的名称,并在需要时采用使函数标签脱颖而出的命名约定。
您的评论是商品。
我发现如果汇编代码(一般代码)在空间上分组在逻辑块中会更容易理解 - 避免文本墙效应。
您以两种不同的方式
我认为您只需两条指令即可执行斐波那契步骤:
xchg eax, ebx
add ebx, eax
如果 eax
是 f(n-1)
并且 ebx
是 f(n)