2.解决除法溢出的问题
前面讲过,div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;进行16位除法的时候,用ax才能出结果的商,dx存储结果的余数,可是,现在有一个问题,如果结果的商大于al或ax所能存储的最大值,那么将如何?
比如下面的程序段:
Mov bh,1
Mov ax,1000
Div bh
进行的是8位除法,结果的商为1000,而1000在al中放不下。
又比如,下面的程序段:
Mov ax,1000h
Mov dx,1
Mov bx,1
Div bx
进行的是16位除法,结果的商为11000h,而11000h在al中放不下。
我们在用div的指令做除法时,很可能会发生上面的情况:结果商过大,超出了寄存器所能存储的范围。当cpu执行div等除法指令的时候,如果发生这样的情况,将引发cpu内部的一个错误,这个错误被称为:除法溢出。我们可以通过特殊的程序来处理这个错误,但在这里我们不讨论这个错误的处理,这是后面的程序所涉及到的内容。下面我们仅仅来看一下除法溢出时发生的一些现象,如图
图中展示了在windows 2000中使用Debug执行相关程序段的结果,div指令引发了cpu的除法溢出,系统对其进行了相关的处理。
好了,我们已经清楚了问题的所在:用div指令做除法的时候可能会产生除法溢出。由于有这样的问题,在进行除法运算的时候要注意除数和被除数的值,比如1000000/10就不能用div指令来计算。那么怎么办呢?我们用下面的子程序divdw解决。
子程序描述
名称:divdw
功能:进行不会溢出的除法运算,被除数为dword型,除数为word型,结果为dword。
参数:(ax)=dword型数据的低16位
(dx)=dword型数据的高16位
(cx)=除数
返回:(dx)=结果的高16位,ax=结果的低16位
(cx)=余数
应用举例:计算1000000/10(F4240H/0AH)
Movax,4240h
Movdx,000fh
Movcx,0ah
Calldivdw
结果:dx=0001h,ax=86a0h,cx=0
提示
给出一个公式:
X:被除数,范围:[0,ffffffff]
N:除数,范围:[0,ffff]
H:X高16位,范围:[0,ffff]
L:X低16位,范围:[0,ffff]
Int():描述性运算符,取商,比如,int(38/10)=10
Rem():描述性运算符,取余数,比如,rem(38/10)=8
公式:X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
实验清单:
assume cs:code,ss:stack
stack segment
dw8 dup (0)
stack ends
code segment
start:movax,4240h
mov dx,000fh
mov cx,0ah
call divdw
mov ax,4c00h
int 21h
divdw:movbx,ax
mov ax,dx
mov dx,0
div cx ;商将放在ax中,余数将放在dx中
push ax ;将商先压入栈
mov ax,bx
div cx ;计算低16位的商
mov cx,dx
pop dx
ret
code ends
end start
实验结果: