我对算术运算如何适用于4位数字感到困惑。这是我正在进行的决赛项目。
我真的很努力去理解大会所以请原谅我,如果我不能正确回答你的问题,但这是我们用于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: ','$'
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
答案 0 :(得分:2)
您需要首先研究如何以位为单位编码整数值,即二进制编码:https://en.wikipedia.org/wiki/Binary_number(这是了解我的答案和问题的必要先决条件)。
代码要求用户输入一个数字,该数字将转换为ASCII。
输入是 ASCII字符。它从从 转换为值0..9
(如果是有效输入,则为ASCII数字)。因为例如ASCII字符'2'
的值为50
(32h
),所以在sub al,48
之后你有al
值2
(不再有字符) ,但整数值,以二进制编码)。
...到目前为止,你设法得到了至少一件事,即用户有一些输入。其他一切都搞砸了。如果你想在汇编代码中进行编码,你必须更精确,机器永远不会猜到你做了什么想要,它总会按照你在代码中要求的那样做。如果你不精确,它会做你不想要的事情。
然后第一个数字是十,所以它乘以10000B。
是的,第一个数字值乘以16.这是小猫死亡的部分,因为您使用mul
乘以2的幂,而不是使用左移4位{{1} }。这是相同的,乘以16,因为2 4 = 16(如果你理解二进制数,你应该能够弄清楚,为什么左移位是乘以2)。
这是我很难理解的部分。当你需要4位数时,你在哪里乘以它?
您的原始来源使用两位数值的packed-BCD编码。
第一个数字"数十"占据前4位,第二位" 1"占用低4位。即用户输入" 34"生成的二进制值为shl al,4
2 = 3 * 16 + 4 = 0011 0100
(十进制)或52
(十六进制)。
对于两个BCD数字,您需要8位。您的旧代码确实将BCD值计算为34h
(8位寄存器),并将其存储在al
地址的存储器中,其中保留单个字节(8位)。
然后当两个值都在内存中并且第二个数字在NUM1
时,代码执行:
AL
它首先使用BCD值执行普通二进制ADD AL, [NUM1]
DAA
ADD [SUM], AL
。如果第二个输入为" 18",那么ADD
发生add 18h, 34h
,这是非法的BCD值,因为第一个数字是AL = 4Ch
(OK),第二个数字是4
(非法)。
然后下一条指令DAA
"Decimal adjust AL after Addition"会将结果修复回有效的BCD,即12
(十进制AL = 52h
,二进制82
),其中第一个BCD数字为5,并且第二个是2.在人类的十进制方式中,这就是你想要的,因为18 + 34 = 52。
最后生成的BCD总和被0101 0010
添加到未初始化的内存SUM
,技术上是另一个错误,虽然在正常情况下内存包含零值,所以它偶然起作用(我写过你了吗?已经,你必须在汇编中精确吗?)。
稍后你会有一些说明:
ADD [SUM], AL
那是第二只死去的小猫,你是一个怪物。实际上{16}计算MOV BL, 10000B ; mov bl,16
DIV BL
就像两只死小猫一样(而且我很慷慨,因为div
比DIV
慢约5-10倍,不仅慢两倍,所以总数是3.将无符号整数除以16的有效方法是MUL
。
shr al,4
这甚至不是有效的x86指令。无论你使用哪种汇编程序,都要快速远离它。 (我强烈怀疑这是emu8086,我个人认为这非常恶劣,因为像这样的事情,emu8086通常会将任何随机文本组装成某些 x86指令,所以除非你经常调试你的代码有了反汇编视图,你甚至不知道你正在使用什么指令。
如何将其扩展为4位数:
1)清理当前版本,删除LEA DL, AL
16。删除复制/粘贴冗余代码,将其转换为程序,使用如下:
mul/div
然后你只需要单个代码就可以从用户那里读取两个字符,并将它们转换为BCD。调试它更正确,比如不要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
执行未初始化的内存,而是ADD
进行设置,而不是mov [SUM],al
。
2)4个BCD打包数字需要16位存储空间。每个数字是4位= 4x4 = 16.(即当4位数值" 1234"位于add
时,ax
的值为ax
= {{ 1}} 2 = 1234h
十进制。
因此,您需要将所有内存预留从字节更改为单词(0001 0010 0011 0100
)。然后,您需要将所有寄存器从8位寄存器(如4660
)更改为16位寄存器,如NUM1 DW ?
。
当然,如果您只是在当前代码中盲目地将al
替换为ax
,那么它将无效,因为al
将完全失败,等等......如果您这样做了按照1)的建议进行适当的清理,你会有一点简单,你仍需要检查每条指令,并以16b的方式修复它,重写代码的某些部分。
例如,可以循环读取用户输入,选择一些备用16b寄存器来累加值,将其重置为零,然后执行4次"读取字符,将其转换为0-9值,移位当前结果为4位,ax
输入值为最低4位" - >结果是4位数的BCD值。
16位mul/div
没有OR
,因此您应该按字节加DAA
,按ax
解析每个加法,再加上处理CF的时间示例num1+num2
。 =很多代码,但这是你的选择,以BCD打包的方式存储值,而不是本机二进制。
DAA
你绝对应该首先在纸上做所有的数学运算,只需要几个示例输入(并将所有3种格式记录在一起,二进制,六进制和十进制,尝试将它们转换为头,你需要练习一下,到能够告诉CPU如何使用CPU位,因此您可以稍后调试代码并检查所有位是否包含预期的结果(来自纸张)。
然后在理解了背后的数学之后,直接在代码中编写它。您应该准确了解每条指令的作用,以及将其添加到代码中的原因。
然后你可以在调试器中验证它。慢慢地,每一条指令,验证它是否真的,你需要什么。
还要考虑抛弃整个BCD打包方案,并使用相当原生的二进制数。然后你可以添加任何4位数值,甚至是5位数的值,因为9999 + 9999 = 19998,这将适合16位(0..65535)。对于5到9位数字,您将需要32位数学。