解决除法溢出问题
例:
mov bh, 1
mov ax, 1000
div bh
进行8位除法,结果商为1000,而1000在al中放不下。
在使用div指令做除法的时候,很可能发生:结果的商过大,超出了寄存器所能储存的范围。当CPU执行div等除法指令的时候,如果发生这样的情况,将引发CPU的一个内部错误,这个错误被称为:除法溢出。
子程序描述:
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。
参数:
(ax) = dword型数据的低16位
(dx) = dword型数据的高16位
(cx) = 除数
返回:
(dx)= 结果的高16位
(ax) = 结果的低16位
(cx) = 余数
例:计算1000000/10 (F4240H/0AH)
mov ax, 4240H
mov dx, 000FH
mov cx, 0AH
call divdw
结果:(dx)= 0001H, (ax) = 86A0H, (CX) = 0
提示:
给出一个公式:
X:被除数,范围[0, FFFFFFFF]
N:除数,范围[0, FFFF]
H:X高16位,范围[0, FFFF]
L:X低16位,范围[0, FFFF]
int(): 描述性运算符,取商
rem(): 描述性运算符,取余数
公式:X/N = int(H/N) * 65536 + [rem(H/N) * 65536 + L] / N
1)其实 65536 就是 10000H,相当于 2^16,也就是说是乘以 2^16,意思就是左移16位。
2)int(H/N) 进行的是16位的除法结果为32位的,然后乘上65536就相当于除法运算的高16位即dx。
3)式中 int(H/N) 和 rem(H/N) 代表着X的高16位的商和余数。
4)等式右边的 int(H/N)*65536 表示将 H/N 的商作为最终结果商的高位字。
5)rem(H/N)*65536+L 表示将 H/N 的余数左移16位,形成一个新的dword数据的高16位,L作为低16位。
[rem(H/N) * 65536 + L]一个新的32位数据。
rem(H/N)*65536+L相当于rem(H/N)高16位和L低16位组成的32位数据。
(dx)= int(H/N)*65536 //相当于当高位储存
(ax) = (rem(H/N)*65536+L)/N的商 32位除法高16位存放dx,低16位存放L
(cx) = (rem(H/N)*65536+L)/N的余数
完整程序:
assume code
code segment
start: mov ax, 4240H
mov dx, 000FH
mov cx, 0AH
call divdw
divdw: //公式前半部分计算
push ax
mov ax, dx
mov dx, 0 //32除法将高位置零,保证ax/cx
div cx // H/N ax保存商
mov bx, ax //保存商
//上次div cx结果的余数为dx,下面32位除法中直接用作被除数的高位
pop ax //获取32位除法的低16位给ax
div cx //计算后的商保存在ax中 直接作为最后返回结果的商的低位
mov cx, dx //保存返回的余数
mov dx, bx //保存返回的商的高位
code ends
end start
x/n = (dx/cx的商(这是8位除法,被除数16位))(高位) + [(dx/cx的余数)(高位) + ax(低位)]/cx(16位除法被除数32位数据)
数值显示
将data段中的数据以10进制形式显示。(将10进制数据转化为ASCII码保存)
子程序描述:
名称:dtoc
功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾。
参数:(ax)= word 型数据 ds:si 指向字符串的首地址
assume cs:code
data segment
db 10 dup (0)
data ends
code segment
start: ax, 12666
mov bx, data
mov ds, bx
mov si, 0
call dtoc
mov ax, 4c00H
int 21H
dtoc: mov bx, 10
mov dx, 0
div bx
mov cx, ax //32/16的除法
add dx, 30H
mov ds:[si], dl
jcxz cx
inc si
jmp short dtoc
s: ret
code ends
end start