输入两个数字并在 NASM 上进行乘除
entering two numbers and multiplying and dividing them on NASM
大家晚上好。我一直在研究这段代码,用户将输入两个数字,然后将它们相乘和相除并显示结果。我正在使用程序来分离进程。我的问题是:不知何故,如果我只做乘法,程序就会结束,一切都会清楚。如果我同时调用这两个过程,程序似乎会在乘法调用之后停留,不会再继续下去。 (比方说 10 和 2。预期的乘法是 20 和商 5,余数为 0,或者 12 和 5,其中乘法是 60,除法是 2 余数 2)也许我的逻辑可能是错误的,或者我的过程调用是错误的,但我想问是否有人可以借给我另一双眼睛,以便我可以了解我的错误可能在哪里。谢谢!!
这是为 NASM 在 DosBox 0.74
上完成的
; Input: Requests two integers from the user.
; Output: Outputs the multiplication and division of the input integers.
%include "io.mac"
.STACK 100H
.DATA
prompt_msg1 db "Please input the first number: ",0
prompt_msg2 db "Please input second number: ",0
mul_msg db "multiplication N1 * N2 is: ",0
div_msg db "Division N1/N2 is: ", 0
rem_msg db "Remainder N1/N2 is: ", 0
.CODE
.STARTUP
PutStr prompt_msg1 ; request first number
GetInt CX ; CX = first number
nwln
PutStr prompt_msg2 ; request second number
GetInt DX ; DX = second number
nwln
;multiplication call
call multi ; returns multiplication in BX
PutStr mul_msg ; display multiplication message
PutInt AX ; display multiplication result
;division call
call divis ; returns division in BX
PutStr div_msg ; display Division message
PutInt BX ; display quotient result
nwln
PutStr rem_msg ; display remainder message
PutInt DX ; display remainder result
done:
.EXIT
multi:
mov AX, CX ; imul= first number
imul AX, DX ; imul = imul * second number
ret ; return
divis:
mov BX, CX
div DX ; idiv = first number / second number
ret ; return
更新:
我能够 运行 代码以及社区提供的修复和建议,感谢您的所有帮助,这里是更新的 运行ning 代码:
; Input: Requests two integers from the user.
; Output: Outputs the multiplication and division of the input integers.
%include "io.mac"
.STACK 100H
.DATA
prompt_msg1 db "Please input the first number: ",0
prompt_msg2 db "Please input second number: ",0
mul_msg db "multiplication N1 * N2 is: ",0
div_msg db "Division N1/N2 is: ", 0
rem_msg db "Remainder N1/N2 is: ", 0
.CODE
.STARTUP
PutStr prompt_msg1 ; request first number
GetInt CX ; CX = first number
nwln
PutStr prompt_msg2 ; request second number
GetInt DX ; DX = second number
nwln
;multiplication call
call multi ; returns multiplication in BX
PutStr mul_msg ; display multiplication message
PutInt AX ; display multiplication result
;division call
call divis ; returns division in BX
PutStr div_msg ; display Division message
PutInt AX ; display quotient result
nwln
PutStr rem_msg ; display remainder message
PutInt DX ; display remainder result
done:
.EXIT
multi:
mov AX, CX ; imul= first number
imul AX, DX ; imul = imul * second number
ret ; return and clear parameters
divis:
mov BX, DX
mov AX, CX
cwd
idiv BX ; idiv = first number / second number
ret ; return and clear parameters
div DX
注定要失败。
在Intel的手册中可以看到:
DIV
Signed divide DX:AX
by r/m16, with result stored in AX
← Quotient, DX
← Remainder.
再往下:
temp ← DX:AX / SRC; (* Signed division *)
IF (temp > 7FFFH) or (temp < 8000H)
(* If a positive result is greater than 7FFFH
or a negative result is less than 8000H *)
THEN
#DE; (* Divide error *)
也就是说,DIV r16
实际上会将DX
和AX
形成的双字除以r16
,商必须适合一个字,否则你会出现除法错误。
DX:AX / DX
会给你一个 0x1nnnn
的商,这不适合一个词。
所以你需要使用不同的除数寄存器,你也应该使用CWD
将被除数sign-extend变成DX:AX
。例如:
mov bx,dx
cwd
div bx
第一个数字在CX
中。第二个数字在 DX
.
divis 除法子程序有 3 个问题。
- 当您应该将第一个数字 (
CX
) 放入累加器 AX
. 时,您将第一个数字 (CX
) 带到了 BX
- 由于word大小的除法实际上是将
DX:AX
除以操作数,所以需要预先初始化DX
- 现在这带来的问题是
DX
不能同时满足两个目的(作为分频器和红利的扩展)。
您可以通过以下方式解决这些问题:
mov bx, dx ;Divider (2nd number) to BX
mov ax, cx ;Dividend (1st number) to AX
cwd ;Extend dividend in DX:AX
idiv bx ;Signed division -> Quotient AX, Remainder DX
PutInt BX ; display quotient result
为了显示商,需要这样写
PutInt AX
来自评论
According to my notes, I understood that once the division has taken place, the remainder will be stored on a smaller size register (lets say if AX is being divided by DX, the quoutient will stay in AX but the remainder will be stored for instance on AL or AH) is my reasoning ok or maybe I am catching something wrong?
根据除数的大小,除法有多种形式。对于股息,您没有自由选择。那总是累加器或累加器及其扩展。
字节除法:将word-sized被除数(总是AX
)除以任何byte-sized除数
div bl ; Divides AX by BL
字除法:将dword-sized被除数(总是DX:AX
)除以任何word-sized除数
div cx ; Divides DX:AX by CX
双字除法:将 qword-sized 被除数(总是 EDX:EAX
)除以任何 dword-sized 除数
div esi ; Divides EDX:EAX by ESI
商总是在被除数的下半部分返回。
字节划分 : AX
的下半部分是AL
分词 : DX:AX
的下半部分是AX
双字除法 : EDX:EAX
的下半部分是EAX
余数总是在股息的上半部分返还。
字节划分 : AX
的上半部分是AH
分词 : DX:AX
的上半部分是DX
双字除法 : EDX:EAX
的上半部分是EDX
大家晚上好。我一直在研究这段代码,用户将输入两个数字,然后将它们相乘和相除并显示结果。我正在使用程序来分离进程。我的问题是:不知何故,如果我只做乘法,程序就会结束,一切都会清楚。如果我同时调用这两个过程,程序似乎会在乘法调用之后停留,不会再继续下去。 (比方说 10 和 2。预期的乘法是 20 和商 5,余数为 0,或者 12 和 5,其中乘法是 60,除法是 2 余数 2)也许我的逻辑可能是错误的,或者我的过程调用是错误的,但我想问是否有人可以借给我另一双眼睛,以便我可以了解我的错误可能在哪里。谢谢!!
这是为 NASM 在 DosBox 0.74
上完成的; Input: Requests two integers from the user.
; Output: Outputs the multiplication and division of the input integers.
%include "io.mac"
.STACK 100H
.DATA
prompt_msg1 db "Please input the first number: ",0
prompt_msg2 db "Please input second number: ",0
mul_msg db "multiplication N1 * N2 is: ",0
div_msg db "Division N1/N2 is: ", 0
rem_msg db "Remainder N1/N2 is: ", 0
.CODE
.STARTUP
PutStr prompt_msg1 ; request first number
GetInt CX ; CX = first number
nwln
PutStr prompt_msg2 ; request second number
GetInt DX ; DX = second number
nwln
;multiplication call
call multi ; returns multiplication in BX
PutStr mul_msg ; display multiplication message
PutInt AX ; display multiplication result
;division call
call divis ; returns division in BX
PutStr div_msg ; display Division message
PutInt BX ; display quotient result
nwln
PutStr rem_msg ; display remainder message
PutInt DX ; display remainder result
done:
.EXIT
multi:
mov AX, CX ; imul= first number
imul AX, DX ; imul = imul * second number
ret ; return
divis:
mov BX, CX
div DX ; idiv = first number / second number
ret ; return
更新:
我能够 运行 代码以及社区提供的修复和建议,感谢您的所有帮助,这里是更新的 运行ning 代码:
; Input: Requests two integers from the user.
; Output: Outputs the multiplication and division of the input integers.
%include "io.mac"
.STACK 100H
.DATA
prompt_msg1 db "Please input the first number: ",0
prompt_msg2 db "Please input second number: ",0
mul_msg db "multiplication N1 * N2 is: ",0
div_msg db "Division N1/N2 is: ", 0
rem_msg db "Remainder N1/N2 is: ", 0
.CODE
.STARTUP
PutStr prompt_msg1 ; request first number
GetInt CX ; CX = first number
nwln
PutStr prompt_msg2 ; request second number
GetInt DX ; DX = second number
nwln
;multiplication call
call multi ; returns multiplication in BX
PutStr mul_msg ; display multiplication message
PutInt AX ; display multiplication result
;division call
call divis ; returns division in BX
PutStr div_msg ; display Division message
PutInt AX ; display quotient result
nwln
PutStr rem_msg ; display remainder message
PutInt DX ; display remainder result
done:
.EXIT
multi:
mov AX, CX ; imul= first number
imul AX, DX ; imul = imul * second number
ret ; return and clear parameters
divis:
mov BX, DX
mov AX, CX
cwd
idiv BX ; idiv = first number / second number
ret ; return and clear parameters
div DX
注定要失败。
在Intel的手册中可以看到:
DIV
Signed divideDX:AX
by r/m16, with result stored inAX
← Quotient,DX
← Remainder.
再往下:
temp ← DX:AX / SRC; (* Signed division *)
IF (temp > 7FFFH) or (temp < 8000H)
(* If a positive result is greater than 7FFFH
or a negative result is less than 8000H *)
THEN
#DE; (* Divide error *)
也就是说,DIV r16
实际上会将DX
和AX
形成的双字除以r16
,商必须适合一个字,否则你会出现除法错误。
DX:AX / DX
会给你一个 0x1nnnn
的商,这不适合一个词。
所以你需要使用不同的除数寄存器,你也应该使用CWD
将被除数sign-extend变成DX:AX
。例如:
mov bx,dx
cwd
div bx
第一个数字在CX
中。第二个数字在 DX
.
divis 除法子程序有 3 个问题。
- 当您应该将第一个数字 (
CX
) 放入累加器AX
. 时,您将第一个数字 ( - 由于word大小的除法实际上是将
DX:AX
除以操作数,所以需要预先初始化DX
- 现在这带来的问题是
DX
不能同时满足两个目的(作为分频器和红利的扩展)。
CX
) 带到了 BX
您可以通过以下方式解决这些问题:
mov bx, dx ;Divider (2nd number) to BX
mov ax, cx ;Dividend (1st number) to AX
cwd ;Extend dividend in DX:AX
idiv bx ;Signed division -> Quotient AX, Remainder DX
PutInt BX ; display quotient result
为了显示商,需要这样写
PutInt AX
来自评论
According to my notes, I understood that once the division has taken place, the remainder will be stored on a smaller size register (lets say if AX is being divided by DX, the quoutient will stay in AX but the remainder will be stored for instance on AL or AH) is my reasoning ok or maybe I am catching something wrong?
根据除数的大小,除法有多种形式。对于股息,您没有自由选择。那总是累加器或累加器及其扩展。
字节除法:将word-sized被除数(总是
AX
)除以任何byte-sized除数div bl ; Divides AX by BL
字除法:将dword-sized被除数(总是
DX:AX
)除以任何word-sized除数div cx ; Divides DX:AX by CX
双字除法:将 qword-sized 被除数(总是
EDX:EAX
)除以任何 dword-sized 除数div esi ; Divides EDX:EAX by ESI
商总是在被除数的下半部分返回。
字节划分 :
AX
的下半部分是AL
分词 :
DX:AX
的下半部分是AX
双字除法 :
EDX:EAX
的下半部分是EAX
余数总是在股息的上半部分返还。
字节划分 :
AX
的上半部分是AH
分词 :
DX:AX
的上半部分是DX
双字除法 :
EDX:EAX
的上半部分是EDX