千哥读书笔记:汇编语言(王爽第四版)第10章实验10第2题divdw程序编写

这道题之所以单独拎出来分析,是因为需要理解的知识比较多。先看看这道题对编写程序的要求:

这道题主要是考查对DIV指令的深入理解和综合运用。先来复习一下原书第169页对DIV指令的描述:

而关于第10章实验10第2题divdw程序的编写,王爽老师给出了一个公式:

并且他在第336页里的附录中给出了这个公式的证明。

只要搞清楚了DIV指在对于除数为16位、被除数为32位的除法原理之后,这道题很多难点就会迎刃而解。

下面,我们来举一个例子,比如我们要计算:1000000 / 10 (即:000F 4240H / 000AH):

按照王爽老师的思路,000F 4240H 作为被除数是个dword型数据,DX保存的是高16位数据000FH,AX保存的是低16位数据4240H,CX保存的是16位数据000AH,这是一个典型的除数为16位、被除数为32位的除法操作。

按照这种操作方式,其除法结果,AX存储着除法操作的商,DX存储着除法操作的余数。但问题在于,如果只进行一次这种除法运算,其结果是186A0H,必然会产生对AX的溢出。

因此,必须采取一种新的算法,简单地说,就是对000F 4240H进行拆分然后进行除法运算,也就是就是“把高位字、低位字,分别除以 CX”。

第一步:用000F 4240H的的高16位000FH 除以 000AH

这时候,首先将000FH的高16位补上0,扩展成32位,也就是成为0000 000FH,然后除以000AH。在这一步的操作中,让DX保存被除数0000 000FH的高16位0000H,让AX保存被除数0000 000FH的低16位000F,然后除以000AH。

其结果,得到000F 4240H的高16位(000FH)的商 0001H、高16位(000FH)的余数 0005H。而商0001H,则保存在AX中,余数 0005H,则保存在DX中。

这一步,就相当于王爽老师提供的公式中:

int(H/N)*65536 和rem(HN)*65536

而将000F 4240H的高16位000FH扩展成32位,然后除以除数000AH,就相当于int(H/N)*65536

而其结果,int(H/N)*65536产生的商 0001H,就保存在AX中;rem(HN)*65536产生的余数0005H,就保存在DX中。

第二步:用 0005 4240H 除以 000AH

为什么要用0005 4240H除以 000AH呢?是因为此时DX已经保存了上一步的除法结果,也就是000F 4240H的高16位(000FH)余数 0005H;而4240H,则是原来的AX保存的000F 4240H的低16位。

这一步,就相当于王爽老师提供的公式中:

rem(HN)*65536+L

000F 4240H的高16位(000FH)余数 0005H,在乘以65536后,再加上000F 4240H的低16位4240H,就得到了0005 4240H。

这里,由于现在的AX已经保存了第一步计算的000F 4240H的高16位(000FH)商0001H,所以,必然会用到一个中间变量(寄存器或栈)来将AX恢复000F 4240H的低16位数据4240H,进行新一轮的除法计算,也就是王爽老师提供的公式中:

[rem(HN)*65536+L]/N

而现在的AX保存着000F 4240H的高16位(000FH)商0001H,所以必须要用另一个中间变量(寄存器或栈)来保存0001H。

这样的计算结果就是:得到了0005 4240H的商 86A0H、余数 0000H。而这时,商86A0H就保存在AX中,符合了王爽老师的要求:(ax) = 结果的低16位;并且余数 0000H就保存在了DX中。

第三步:将000F 4240H的高16位(000FH)除以000AH的商0001H保存在DX中,将DX中余数0000H保存在CX中。

从而实现:(dx) = 结果的高16位,(cx) = 余数。

这种计算方法,可以用小学用的“竖式”来描述:

小结一下:

第一步:用 0000 000FH 除以 000AH,得到高位商 0001H、高位余数 0005H。

第二步:用 0005 4240H 除以 000AH,可得到低位商 86A0H、低位余数 0000。

最后,回到divdw程序编写的要求上:

应用举例:计算 1000000/10(F4240H/0AH)

mov ax,4240H

mov dx,000FH

mov cx,0AH

call divdw

结果:(dx)=0001H,(ax)=86A0H,(cx)=0

在这个初始条件中,AX保存了低16位数据4240H,DX保存了高16位数据000FH,DX与AX联合作为被数除, CX保存了0AH并作为除数,然后要通过call指令来调用divdw,最终实现DX保存结果(商)的高16位0001H,,AX保存结果(商)的低16位86A0H,CX保存余数0。

根据我们前面的思路,贴出divdw程序的完整代码:

================

;计算1000000/10(F4240H/0AH)
;使用公式:X/N = int(H/N)*65536 + [rem(H/N)*65536+L]/N
assume cs:code
code segment
    mov ax,4240h
    mov dx,000fh
    mov cx,0ah

call divdw
    mov ax,4c00h
    int 21h

divdw: mov bx,ax;将AX中保存了被除数F4240H的低16位数据4240H,保存到BX中,BX作为临时变量。
       mov ax,dx;将DX中保存了被除数F4240H的高16位数据000FH,保存到AX中,AX作为除法运算被除数的低16位。
       mov dx,0;将DX清零,作为除法运算被除数的高16位。
       div cx     ;CX作为除数,这时被除数是32位的,即0000000FH,DX是0000H,AX是000FH。运行后,DX存放余数,AX存放商。
       push ax    ;通过压栈操作,保存AX中的商,即是最后商的高16位。
 
       mov ax,bx  ;将临时变量BX中的被除数F4240H的低16位数据4240H,恢复到AX,作为新一轮除法运算中被除数的低16位数据。
       div cx     ;此时在上一轮除法运算中DX中的余数,作为被除数的高16位,AX中的数据作为被除数的低16位,进行除法运算。
       mov cx,dx  ;得到的余数保存在DX中,然后通过DX保存到cx
       pop dx     ;将最后商的高16位弹出栈,保存在DX中,成为最后商的高16位,低16位已经在ax中。
       ret
code ends
end

================

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值