Assembly 如何在汇编中对4位数字进行算术运算?
我对四位数的算术运算感到困惑。这是我正在做的期末考试项目 我真的在努力理解汇编,所以如果我不能正确回答您的问题,请原谅我,但这是我们用于2位输入算术运算的代码。我想知道当输入为4位数字时我如何使用它Assembly 如何在汇编中对4位数字进行算术运算?,assembly,Assembly,我对四位数的算术运算感到困惑。这是我正在做的期末考试项目 我真的在努力理解汇编,所以如果我不能正确回答您的问题,请原谅我,但这是我们用于2位输入算术运算的代码。我想知道当输入为4位数字时我如何使用它 .MODEL SMALL .STACK 200 .DATA RADIX DB 10 TEMP DB 10 DUP(?) CRLF DB 0DH,0AH,'$' PROMPT1 DB 'Input the 1st 2digit number: ',
.MODEL SMALL
.STACK 200
.DATA
RADIX DB 10
TEMP DB 10 DUP(?)
CRLF DB 0DH,0AH,'$'
PROMPT1 DB 'Input the 1st 2digit number: ','$'
PROMPT2 DB 'Input the 2nd 2digit number: ','$'
PROMPT3 DB 'The sum of two numbers is: ','$'
PROMPT4 DB 'The difference of two numbers is: ','$'
PROMPT5 DB 'The product of two numbers is: ','$'
PROMPT6 DB 'The quotient of two numbers is: ','$'
PROMPT7 DB 'The remainder of two numbers is: ','$'
NUM1 DB ?
NUM2 DB ?
NUM3 DB ?
SUM DB ?
DIFF DB ?
PROD DB ?
QUO DB ?
REM DB ?
.CODE
.STARTUP
LEA DX,PROMPT1
MOV AH,09H
INT 21H
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV CH, AL
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV CL, AL
MOV AL, 10000B
MUL CH
XOR AH, AH
OR AL, CL
MOV NUM1, AL
MOV AL, 00H
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT2
MOV AH,09H
INT 21H
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV CH, AL
MOV AH, 01H
INT 21H
SUB AL, 30H
MOV CL, AL
MOV AL, 10000B
MUL CH
XOR AH, AH
OR AL, CL
MOV NUM2, AL
ADD AL, NUM1
DAA
ADD SUM, AL
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT3
MOV AH,09H
INT 21H
MOV AL, SUM
XOR AH, AH
MOV BL, 10000B
DIV BL
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH, 02H
INT 21H
MOV AL, SUM
XOR AH, AH
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH,02H
INT 21H
MOV AL,00H
MOV AL,NUM1
SUB AL,NUM2
DAS
MOV DIFF,AL
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT4
MOV AH,09H
INT 21H
MOV AL, DIFF
XOR AH, AH
MOV BL, 10000B
DIV BL
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH, 02H
INT 21H
MOV AL, DIFF
XOR AH, AH
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH,02H
INT 21H
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT5
MOV AH,09H
INT 21H
MOV AL, 00H
MOV DL, 00H
MOV AL, NUM1
MOV DL, NUM2
MUL DL
MOV PROD, AL
MOV CX, 00H
XOR BH, BH
XOR SI, SI
DISPX1:
MOV DX, 00
DIV BX
MOV TEMP[SI], DL
INC SI
INC CX
OR AX, AX
JNZ DISPX1
DEC SI
MOV AL, PROD
DISPX2:
MOV DL, TEMP [SI]
MOV AH, 06H
ADD DL, 30H
INT 21H
DEC SI
DEC CX
JNZ DISPX2
MOV AX,00H
MOV BX,00H
MOV AL,NUM1
MOV BH,NUM2
DIV BH
MOV QUO,AL
MOV REM,AH
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT6
MOV AH,09H
INT 21H
MOV AL, QUO
XOR AH, AH
MOV BL, 10000B
DIV BL
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH, 02H
INT 21H
MOV AL, QUO
XOR AH, AH
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH,02H
INT 21H
LEA DX,CRLF
MOV AH,09H
INT 21H
LEA DX,PROMPT7
MOV AH,09H
INT 21H
MOV AL, REM
XOR AH, AH
MOV BL, 10000B
DIV BL
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH, 02H
INT 21H
MOV AL, REM
XOR AH, AH
AND AL, 0FH
ADD AL, 30H
LEA DL, AL
MOV AH,02H
INT 21H
.EXIT
END
您需要首先研究整数值如何以位进行编码,即二进制编码:(这是理解我的答案和您的问题的必要先决条件) 该代码要求用户输入一个数字,该数字将转换为ASCII码 输入为ASCII字符。它从ASCII转换为值
0..9
(如果输入有效,则转换为ASCII数字)。因为例如ASCII字符'2'
具有值50
(32h
),所以在sub al之后,48
中有al
值2
(没有更多字符,而是二进制编码的整数值)
。。。到目前为止,至少有一件事是正确的,那个就是用户提供了一些输入。其他一切都搞砸了。如果你想在汇编中编写代码,你必须更加精确,机器永远不会猜到你想要什么,它总是按照你在代码中要求的去做。如果你不精确,它会做你不想做的事情
然后第一个数字是十,所以它乘以10000B
是的,第一个数字值乘以16。这是小猫死亡的部分,因为您使用了mul
乘以二的幂,而不是使用左移位4位shl al,4
。这和乘以16是一样的,因为24=16(如果你理解二进制数,你应该能够理解,为什么向左移位的位乘以2的幂)
这是我很难理解的部分。当你需要4位数字时,你在哪里乘法
您的原始源代码使用两位数的编码
第一位数字“十”占据前4位,第二位数字“一”占据低4位。即,对于用户输入“34”,结果二进制值为十进制的0010100
2=3*16+4=52
,或十六进制的34h
对于两个BCD数字,需要8位。您的旧代码将BCD值计算到al
(8位寄存器)中,并将其存储到NUM1
地址的内存中,其中保留了一个字节(8位)
然后,当两个值都在内存中且第二个数字在AL
中时,代码执行以下操作:
ADD AL, [NUM1]
DAA
ADD [SUM], AL
它首先使用BCD值添加普通二进制。如果第二个输入为“18”,则会出现add 18h、34h
,并且AL=4Ch
,这是非法的BCD值,因为第一个数字是4
(确定),第二个数字是12
(非法)
然后,下一条指令将把结果修复回有效的BCD,即AL=52h
(十进制82
,二进制01010010
),其中第一个BCD数字是5,第二个是2。以人类十进制的方式,这就是你想要的,因为18+34=52
最后,通过ADD[sum],AL
将生成的BCD和添加到未初始化的内存sum
,这在技术上是另一个错误,尽管在正常情况下,内存包含零值,所以它是偶然工作的(我是否已经写给你了,你必须在汇编中精确)
随后,您将获得以下几条说明:
MOV BL, 10000B ; mov bl,16
DIV BL
那是第二只死猫,你是个怪物。实际上,div
比两只死小猫慢了16次(我很慷慨,因为div
比MUL
慢了5-10倍,不仅慢了两倍),所以总数是3。将无符号整数除以16的有效方法是shral,4
这甚至不是有效的x86指令。不管你用的是什么汇编程序,赶快离开它。(我强烈怀疑这就是emu8086,我个人认为它非常残暴,因为这样的事情,emu8086通常会将任何随机文本汇编成一些x86指令,因此除非您使用反汇编视图大量调试代码,否则您甚至不知道您使用的是什么指令)
如何将其扩展到4位:
1) 清除当前版本,按16删除mul/div
。删除复制/粘贴冗余代码,将其转换为过程,以便像以下那样使用:
call getInputValue ; returns two digit BCD in AL
mov [NUM1],al ; NUM1 from user
call getInputValue ; returns two digit BCD in AL
mov [NUM2],al ; NUM2 from user
然后,您只需要一个代码就可以从用户处读取两个字符,并将它们转换为BCD。调试它以使其更加正确,例如不要将添加到未初始化的内存中,而是执行mov[SUM],al
来设置它,而不是添加
2) 4 BCD压缩数字需要16位存储。每个数字为4位=4x4=16。(即,当4位数字值“1234”位于ax
时,ax
的值为1234h
=0001 0010 0011 0100
2=4660
十进制
因此,您需要将所有内存保留从字节更改为字(num1dw?
),然后需要将所有寄存器从8位寄存器(如al
)更改为16位寄存器(如ax
)
当然,如果您在当前代码中盲目地将al
替换为ax
,它将不起作用,因为mul/div
将完全失败,等等。如果您按照1)中的建议进行了适当的清理,您的操作会简单一点,仍然需要检查每个指令,并以16b的方式修复它,重写部分代码
例如,用户输入可以在循环中读取,选择一些备用16b寄存器累积值,将其重置为零,然后执行4次“读取字符,将其转换为0-9值,将当前结果左移4位,或
输入值为最低4位”->结果是4位压缩BCD值
没有DAAcall getInputValue ; returns two digit BCD in AL
mov [NUM1],al ; NUM1 from user
call getInputValue ; returns two digit BCD in AL
mov [NUM2],al ; NUM2 from user
mov al,[NUM1]
add al,[NUM2] ; add low 2 digits of NUM1 and NUM2
daa ; bcd fix
mov [SUM],al ; store low 2 digits
mov al,[NUM1+1]
adc al,0 ; add CF to upper 2 digits
daa ; bcd fix
jc addOverflow_needs5digits ; when result is > 9999
add al,[NUM2+1] ; add upper two digits of NUM2
daa ; bcd fix
mov [SUM+1],al ; store upper 2 digits
jc addOverflow_needs5digits ; when result is > 9999
; all those DW accessed by AL may need "BYTE PTR" override in MASM