汇编语言中div运算如果被除数为32位,除数则为16位,被除数放在DX和AX中,商放在AX中,余数放在DX中。如果被除数为16位,除数则为8位,被除数放在AX中,商放在ah,余数放在al。
但会产生一个问题,那就是当除出来的商大于AX或者AH的时候,就会产生除法溢出的错误。例如1000/1,被除数可以放在16位的AX中,1可以放在8位的寄存器中,得到的商为1000,超过了AH能容纳的最大值,因此会造成除法溢出的问题。
王爽的书中提供一个公式,可以避免除法溢出的问题
子程序要求
名称:divdw
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型
参数:(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:(ax)=商的低16位
(dx)=商的高16位
(cx)=余数
公式
X:被除数,范围:[0, FFFFFFFF]
N:除数,范围:[0, FFFF]
H:X高16位,范围:[0, FFFF]
L:X低16位,范围:[0, FFFF]
int():描述性运算符,取商,比如,int(38/10)=3
rem():描述性运算符,取余数,比如,rem(38/10)=8
公式:X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N
分析
首先来看看公式中的65536,很多新手的话可能不能理解这个65536是什么意思,其实65536就是10000H,相当于2^16,也就是说是乘以2^16,意思就是左移16位。
式中int(H/N)和rem(H/N)代表着X的高16位的商和余数。
等式右边的int(H/N)*65536表示将H/N的商作为最终结果商的高位字。
rem(H/N)*65536+L表示将H/N的余数左移16位,形成一个新的dword数据的高16位,L作为低16位。
最后的结果是DX中存放int(H/N)的结果,AX中存放(rem(H/N)*65536+L)/N的商,CX中存放(rem(H/N)*65536+L)/N的余数。
子程序
;子程序描述
;名称: divdw
;功能: 进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型.
;参数: (dx)=dword型数据的高16位 (ax)=dword型数据的低16位 (cx)=除数
;返回: (dx)=结果的高16位 (ax)=结果的低16位 (cx)=余数
;应用举例: 计算1000000/10(F4240H/0AH)
divdw:
push ax ;被除数的低16位入栈
mov ax,dx
mov dx,0
mov cx,10
div cx ;得到的结果商放在AX中,余数放在DX中
mov cx,ax;暂时保存商
pop ax ;取出低16位的值
push cx ;保存商入栈
mov cx,10
div cx
mov cx,dx ;余数放入cx中
pop dx ;商的高16位存入dx中,ax中的结果就为商的低16位
ret