一、公式推导
在编写程序前首先需要理解公式是如何推导的。
如上图所示,我们首先需要理解除法运算是如何可以推导为该公式。
设一个十进制数:121作为被除数,除数为3,我们获取123/3的商及余数。
121/3=(120+1)/3=(10*12+1)/3=(10*4*3+10*0+1)/3
=10*4+(0*10+1)/3
可以发现,商为40,余数为1。
在设一个较为复杂的十进制数:12391,除数为4,我们获取12391/4的商及余数
12391/4=(12390+1)/4=(10*1239+1)/4
=[10*(1228+11)+1]/4
=[10*(4*307+11)+1]/4
=[10*4*307+10*11+1]/4
=10*307+(10*11+1)/4
=3070+(111)/4
=3070+(4*27+3)/4
可以看到,最后的商为3097,余数为3。假设X只右移一位,即进位1,可列出下列公式:
X/N=[10*X1+a]/N
=[10*(X2+b)+a]/N
=10*(X2/N)+(10*b+a)/N
;其中,X1为右移后的最小可被10整除的数,X2为N的整数倍。
十进制中10作为进位,而16进制中,16作为进位,只需要把10改成16,公式依然成立。
我们设一个十六进制数0111,除数为3。右移一位变为011。设{x}为十六进制数的十进制表示。如下所示:
X/N=[16*{X1}+a]/N
=[16*({X2}+b)+a]/N
=16*({X2}/N)+(16*b+a)/N
;其中,X1为右移后的最小可被16整除的数,X2为N的整数倍。
011H=17,17=15+2,故N=3,X1=011H,X2=0FH,b=2H,a=1H。
X/N=16*(0FH/3H)+(16*2H+1H)/3H
=50H+(20H+1H)/3H
=50H+(33/3)
=50H+BH+0H
商为5BH,余数为0H。
当被除数X=a7a6a5a4a3a2a1a0时,右移n位,则乘以16n。由于寄存器ax,dx为16位寄存器,这里我们右移4位,能够保证寄存器不溢出。
X/N=[164{X1}+a]/N
=[164({X2}+b)+a]/N
=164*({X2}/N)+(164*b+a)/N
;其中,X1为右移4位后的最大可被164整除的数,X2为X1/N后得到的最大整数,b为X1/N的余数。a为低四位。
这里右移四位后实际上就是高4位的值,X2/N等价于int(H/N),a等价于L,b等价于rem(H/N)。
二、寄存器
ax存储商,dx存储余数,寄存器大小为2个字节。
1、首先,我们做高位的除法,此时被除数在2个字节范围内,故而不会发生除法溢出的问题。得到了高位除法运算后的商和余数。
2、再对低4位被除数做除法运算,得到了低位除法运算后的商。
3、现在需要考虑的是如何存储这些数据,并合成为最终结果。
三、思路
1、最终我们需要让dx寄存器存储高位的商,ax寄存器存储低位的商。第一次进行除法运算时,ax中实际存储的是高位的被除数,而商存储在ax中,余数存储在dx中。此时ax的值为int(H/N)。
2、根据公式,我们需要让低4位被除数与高位的余数相加,然后与除数相除。此时进行的是32为除法运算,dx为高位,ax为低位。根据附录5的证明,此时并不会发生溢出。
3、运算结束后dx存储余数,ax存储商。
4、第一次存储的商与第二次存储的商相加,得到最终的结果。
四、程序
;关键代码
mov cx,N;(除数)
mov ax,H;(低位)
mov dx,L;(高位)
push ax
mov ax,dx
mov dx,0
div cx
mov bx,ax;第一次除法运算的商
pop ax
div cx
mov dx,dx;(余数)
mov dx,bx(第一次除法运算的商)
;此时dx ax为32位的商,cx为余数。
完整代码:
assume cs:code
stack segment
db 8 dup(0)
stack ends
code segment
start:
mov ax,stack
mov ss,ax
mov sp,16
mov ax,4240H
mov dx,000FH
mov cx,10
call divw
mov ax,4c00h
int 21h
divw:
push ax ;低位入栈
mov ax,dx ;16位被除数
mov dx,0 ;高位置为0
div cx ;第一次除法运算
mov bx,ax ;第一次除法运算的商int(X/N)存入bx
pop ax ;低位出栈
div cx ;第二次除法运算
mov cx,dx ;余数rem(X/N)*16^4存入cx,第二次除法运算得到的商存入低位寄存器ax
mov dx,bx ;由于dx存储高位的商,等价于bx左移4位,即int(X/N)*16^4
ret ;此时dx ax即为得到的商,cx为余数
code ends
end start