题目描述
输入一个最大长度为4的十六进制数,将其转换成10进制输出。
其中我们需要检测十六进制输入的正确性,比如大小写、特殊字符和数字的判断。
解决方式
程序分为两个部分,首先是处理我们的输入,以及通过除法计算十进制数的过程。
data SEGMENT USE16
data ENDS
stack SEGMENT USE16
db 32 dup(?)
stack ENDS
code SEGMENT USE16
ASSUME CS:CODE, DS:DATA, SS:STACK
main PROC
start:
mov ax,data
mov ds,ax
xor bx,bx
mov dl,4
loop1:
cmp dl,0
jz next
mov ah,1
int 21h
cmp al,13
jz next
;数字
cmp al,30h
jb loop1
cmp al,39h
ja big
sub al,30h
dec dl
jmp fin
big:
cmp al,65
jb loop1
cmp al,70
ja small
sub al,37h
dec dl
jmp fin
small:
cmp al,97
jb loop1
cmp al,102
ja loop1
sub al,87
dec dl
fin:
mov cl,4
shl bx,cl
and ax,0fh
add bx,ax
jmp loop1
next:
cmp dl,0
jnz no_need
mov dl,10
mov ah,2
int 21h
mov dl,13
mov ah,2
int 21h
no_need:
mov ax,bx
mov cx,10
xor bx,bx
turn_in:
xor dx,dx
div cx
push dx
inc bl
cmp ax,0
jz turn_out
jmp turn_in
turn_out:
pop dx
add dl,30h
mov ah,2
int 21h
dec bl
cmp bl,0
jnz turn_out
mov ah,4ch
int 21h
main ENDP
code ENDS
end start
输入(next标号之前)
首先看一下输入部分,我们需要解决四个问题。
- 输入结束有两个标准,一个是输入满四位,另一个是检测到回车
- 不论是大小写还是数字,我们都需要读入(记住读入的是ascii,还需要处理一下)
- 对于其他字符,我们需要跳过,进行下一个循环
- 如果是需要读入,我们就需要将原来的数据左移四位(乘16),然后加上处理过的输入。
首先,我们将dl作为计数器,每一次循环观测dl是否为0,同时读入一个数据,判断是否为回车(ascii为13)。
然后我们判断一下输入的正确性问题。这里我画出了ascii表中数字和大小写的排列顺序。
所以我们是这样判断的:
这就是我们的跳转流程。
(为什么要减这些数,自己查一下ASCII,当增强记忆了)
与其说这个结构是if_else,我倒是感觉更像case,其中的jmp指令就像是break,如果没有break,那么我们就会将下一个分支也执行了,导致出错。
在每一次读入之后,我们说白了其实是将之前的作为高位,然后加入低位。
(比如输入十进制123,我们是先将12左移一位,也就是乘十,然后加三)
这里也一样,不过我们需要bx右移四位(寄存器中为二进制数),然后加上存储在al的值。
另外附上我们的测试案例:(1e23),可以看到BX值正确。
输出
这里因为是十进制的输出,我们之前还可以通过进制偷懒(指输出二进制或十六进制数),现在是不行了。
这里我们采用每一次除以10,将余数压栈的方式,存储好结果的相反顺序,然后pop到dl,进行输出。
这里先讲一下汇编的乘除法吧。
对于两个二进制数来说,a位乘以b位的,那么结果一定不会大于a+b位。
(2a-1-1和2b-1-1一定小于2a+b-1)
我们在除的过程中也是如此,因为bx是16位,我们的除数10为4位,所以我们的结果是不能用al和ah放下的(余数小于等于除数的位数,商小于等于被除数位数减除数位数。)
那么我们还有一种办法,就是将DX:AX作为被除数,将CX作为除数,这样商在AX,余数在DX,就能放下了。
如果是再次除,我们只需要将dx置零。
效果:
通过这样一个案例,我们知道了选择除法范围也是有考量的,不是怎么方便怎么来的。
turn_in循环就实现了每一次将ax寄存器除以十,商在ax,余数在dx,将dx压栈后清零,再次进行除法。
每一次除法我们都将计数器bl自增,方便出栈使用。
当ax寄存器为0,我们结束循环,进入到输入(turn_out)部分。
turn_out部分我们每一个循环都弹出一个dx,因为dx的余数一定是小于10的,我们直接加30h输出即可。
这里写的不是太好,其实完全可以将bl放在cl中,然后直接loop的。
补充
这部分最重要应该就是跳转逻辑和我们的除法部分。
另外讲解一下no_need标签部分:
因为我们如果是输入满四位,会强制性结束输入,这时就没有我们的回车显示了,所以我加了一个判断来进行换行,看着比较舒服,没别的意思。
然后补充一下自己的十进制输入转二进制/十六进制输出的案例。