10.2 解决除法溢出的问题
给出的公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
参数: ax存放被除数低16 dx存放被除数高16 cx存放除数
分析:
*65536相当于进到高16位 rem(H/N)*65536不用算,因为算H/N的时候已经把这个结果算出来了,存放在dx,相当于只要计算H/N 和L/H
完整代码:
assume cs:code,ss:stack
stack segment
dw 10 dup(0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,20
mov ax,4240h
mov dx,0fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw:
;X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
;分析 *65536相当于进到高16位 rem(H/N)*65536不用算,因为算h/n的时候已经把这个结果算出来了,存放在dx,相当于只要计算h/n 和l/n
;ax存放被除数低16 dx存放被除数高16 cx存放除数
push ax
mov ax,dx ;取出高16位
mov dx,0 ;被除数高16位置0,因为要计算H/N
div cx ;int()H/N 商结果存放ax,余数结果存放dx,一切都是那么的恰到好处
mov bx,ax ;存放结果
pop ax ;取出低16位
div cx ;L/N 商ax 余数dx
mov cx,dx ;存储余数
mov dx,bx ;存储低16位
ret
code ends
end start
实验10.3 数值显示
这里要用到前面的子程序showptr(显示以0结尾字符串在显示器上),将数值显示出来。
我们也需要写一个通用的小程序dtoc,用来将数据转化为10进制的ASCII码
算法规则:
12345/10=1234 余数5 --> 5+30H=35H 入栈
1234/10=123 余数4 -->4+30H=34H 入栈
123/10=12 余数3 -->3+30H=33H 入栈
12/10=1 余数2 -->2+30H=32H 入栈
1/10=0 余数1 -->1+30H=31H 入栈 到此结束计算
然后统统出栈到data段之中就可以了。
最后再调用showptr小程序就可以显示到屏幕上了.
完整代码:
assume cs:code,ds:data,ss:stack
data segment
db 20 dup(0)
data ends
stack segment
dw 20 dup(0)
stack ends
code segment
start:
mov bx,data
mov ds,bx
mov bx,stack
mov ss,bx
mov sp,40
mov ax,12345
mov si,0
call dtoc ;将word型数据转变成十进制字符串,字符串以0结尾,存放于data段
mov dh,12
mov dl,64
mov cl,02h
mov si,0
call showptr ;显示字符串 dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
mov ax,4c00h
int 21h
dtoc:
push ax
push bx
push cx
push dx
push di
push si
mov bx,10;除数为10
mov di,0 ;计数器置0
s0:
mov dx,0 ;被除数高位置0
div bx ;做除法 dx存放余数 ax存放商
add dx,30h ;余数加30h
push dx ;存放ascii码,入栈
inc di ;计数器加1
;判断商是否为0
mov cx,ax
jcxz dtoc_ok
jmp short s0 ;跳转回去继续做除法直到商为0
dtoc_ok:
;inc di
mov cx,di ;计数器存进cx做循环
;inc cx
s2:
pop ds:[si];出栈 弹出到data空间
inc si ;指针后移
loop s2 ;结束循环表示出栈成功
;归还寄存器
pop si
pop di
pop dx
pop cx
pop bx
pop ax
ret
showptr: ;将用到的寄存器统统存储一遍,后续结束小程序时全部返还
push di
push dx
push cx
push si
push ds
push es
push ax
show:
;将字符串显示在屏幕上,dh是行,dl是列,cl是颜色,ds:si指向字符串首地址
;1.首先计算显存位置
sub dh,1 ;dh减一
mov al,dh ;做乘法运算
mov ah,160
mul ah ;行数减一乘以160 最后将结果ax加上dl即可
mov dh,0
add ax,dx ;ax此时存放写入的地址位置
mov di,ax ;作为显存指针使用
mov ax,0b800h
mov es,ax ;将显存地址写入es
;2.确定颜色属性
mov dh,cl ;将颜色属性赋值高位过去
;3.写入字符串,ds:si指向字符串首地址,需要将字符串存放到dl中
show0:
;这里要利用jcxz了
mov ch,0
mov cl,ds:[si]
jcxz show_ok
mov dl,ds:[si] ;获取字符串字节
mov es:[di],dx ;将dx写入到es:[di]中去 也就是显存地址
inc si ;字符串指针后移
add di,2 ;显存地址后移
jmp short show0 ;跳转回去
show_ok:;出口
pop ax
pop es
pop ds
pop si
pop cx
pop dx
pop di
ret
code ends
end start
效果如下图