王爽汇编第三版实验10.2 浅析

题目我这里就不写了,相信大家点进这篇文章,手头上肯定是有题目的。

这道题目,我开始的时候,怎么也做不出,因为什么?因为要*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


欢迎大家一起讨论。

猜你喜欢

转载自blog.csdn.net/freedomosfortjm/article/details/75324715