题目我这里就不写了,相信大家点进这篇文章,手头上肯定是有题目的。
这道题目,我开始的时候,怎么也做不出,因为什么?因为要*65536,王爽这本书上说mul指令,两个相乘的数要么都是8位,要么都是16位,然而65536转换成十六进制是10000H,当时我就有点懵。
我拿书上的公式在纸上算了几遍,也就是 X/N =int (H/N)*65535+rem[(H/N)*65536+L]/N
其中X为被除数
N为除数
H为被除数高16位
L为被除数低16位
int()为取商
rem()为取余数
我发现前面的取商,但不乘65536(10000H)确实是等于得数的高16位,比如书上例子
mov ax,4240H
mov dx,000FH
mov cx,0AH
F/A=1余5。然后书上的最终结果为DX=0001H,这时候我突然想起前面书上说的“左移4位”,那么65536=2^16,就是左移16位了,为什么要左移16位?因为这个结果是高16位,他后面还有一个低16位,自然要左移16位了。
再由于高位单独保存在一个寄存器中,所以在写代码的时候是不用左移的,因为高位和低位是分开保存的。
现在高位解决了,比较重点的是结果的低16位,刚开始思考这里的时候,我真的毫无头绪,后面我也是慢慢地想:
除法如果除数是16位,那么被除数一定就是32位的,所以“rem(H/N)*65536+L”是32位的。
我们先来看看,还是上面的例子,5H*(10000H)+4240H 看到这里你想到了什么?是不是和刚才的1*10000H很像?对了,既然乘法会溢出,那么说明我们思路是错的,想错了。我们延续刚才高位的思路,把5H看成高位,把4240H看成低位,那么就OK了。5H本来就保存在DX中,4240H也是保存在AX中,所以,直接div cx,那么得到的商在AX中,余数在DX中,这个AX就是我们结果的低16位。而这个DX,就是结果的余数了,为什么?因为前面的高位计算不可能出现余数,所以后面的余数就肯定是结果的余数了。
下面放上代码:
DATAS SEGMENT
dw 1 dup(0)
DATAS ENDS
STACKS SEGMENT
dw 8 dup(0)
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,SS:STACKS
START:
MOV AX,STACKS
MOV SS,AX
MOV SP,10H
MOV AX,DATAS
MOV DS,AX
MOV BX,0
MOV AX,4240H
MOV DX,0FH
MOV CX,0AH
CALL divdw
MOV AX,4C00H
INT 21H
divdw:
push ax ;将被除数低16位进栈 因为等下要用到
mov ax,dx ;我们要做32位除法 所以要清空高16位寄存器
mov dx,0
div cx ;得到的商在ax 余数在dx
mov [bx],ax ;暂时保存商 商为式子的商的高16位 这里的商不用左移16位 因为他是保存在另外一个寄存器的
pop ax ;将ax出栈 因为等下要用到
div cx ;现在把dx看做高16位 ax看做低16位 我们做除法 除数是cx
;现在我们得到了一个商,它为式子的低16位 保存在AX中 余数保存在DX中
mov cx,dx ;把余数赋值给CX
mov dx,[bx] ;把高16位得数取出来 赋值给dx
ret ;关键的思想是 把rem(H/N)看为一个数的高16位 那么就不用除65536 这样就不会出现乘法溢出了
CODES ENDS
END START
欢迎大家一起讨论。