2、解决除法溢出的除法
题目描述
实验10 2、解决溢出的除法.png
算法依据:第二次除法不会产生溢出
-
参考《汇编语言(第三版)》附注5
第二次除法不会产生溢出.png
实际输出
解决除法溢出的除法.png
完整源码
assume cs:code,ss:stack
stack segment
dw 1 dup (0)
stack ends
code segment
start: mov ax,4240H
mov dx,000FH
mov cx,0AH
call divdw
mov ax,4c00H
int 21H
divdw: push ax
mov ax,dx
mov dx,0
div cx
mov bx,ax
pop ax
div cx
mov cx,dx
mov dx,bx
ret
code ends
end start
代码说明
汇编指令 寄存器 栈 内容变化
解题思路
- 书上提示大家去看附注5,附注5推导了公式,其中对于解题最为有用的是这一句话 H/N产生的余数是绝对不能丢的
- 如何计算 H/N?更准确地说通过 H/N 我们想得到什么?
我们的 div指令 只能处理
32位 ÷ 16位
16位÷ 8位
这两种形式的除法
CX=000AH 是16位
因此 H/N 得用 32位 ÷ 16位 来进行
H 表示的dd数据的高16位,本题中是 000FH
要拓展成一个32位的数据,也是要变成 0000 0000FH
从寄存器的角度上来说,就是要改写DX 以及 AX 寄存器
最终使得
DX | AX
------------
0000 000F
相当于用这个新的 dd型的数据(0000 000FH)来进行除法运算
DX 寄存器
在除法运算之前表示dd数据的高16位
在进行除法运算之后存着 余数
不同时期,角色不同
AX 寄存器
在除法运算之前表示dd数据的低16位
在进行除法运算之后存着 商
这个也是不同时期,角色不同
而对于 H/N
商,我们需要留下的,会出现最终结果里!
余数,我们也要!
除法运算结束之后,我们顺利得到了余数和商
DX | AX
------------
0005 0001
余数 商
这个商是最终商的高16位
我们使用BX寄存器保存起来,
这样DX、AX寄存器又可以拿来做除法运算了
- 最终结果从何而来?
DX | AX
------------
0005 0001
余数 商
栈中在一开始保存的AX内容还原一下
并且,换一个角色角度看到DX与AX
这时候它是一个全新的dd型数据
DX | AX
------------
0005 4240
高位 低位
使用这个dd型数据,可以直接进行不溢出的除法
再一次得到一个余数(最终余数),以及一个商(最终商的低16位)
DX | AX
------------
0000 86A0
余数 商
把各个数据组合成题目需要的形式
用DX存高16位的最终商,从BX寄存器中取回来
用AX存低16位的最终商,不用变动了
用CX存最终余数,从DX寄存器中拿来
DX | AX
------------
0001 86A0
商高16位 商低16位
CX
-----
0000
余数
- H/N 是本题的突破口
H 是32位dd型数据的高16位部分
H/N 的商,记为 a ,可以用 16位表示
H/N 的余数,记为 b,可以用 16位表示
H/N = a...b
a 也是最终的商的高16位
但是 b 不能省略,b结合L,相当于 b x FFFFH + L
FFFFH = 65536D
如附注5所证明的
b/n ≤ FFFFH - 1/n
不会产生进位,也就是不会产生溢出,可以直接用 32位÷16位进行除法
代码参考
感想
算法中的数学部分,告诉并保证了我们这样做是正确的。然而,编程直到最后解决问题不仅仅是掌握数学就一步登天了,纵然我知道了什么才是对的,我也要知道如果才能做对,这就是做正确的事情(数学)和正确地做事之间的区别。要想知道自己做的事情是正确的,我需要学习数学。更大一部分,要正确地做事,我还需要知道汇编语言除法指令中寄存器的角色安排,我还需要思考解决这个问题本身的指令顺序安排,这大把东西一样既不简单(复杂)也不容易(困难)。海阔凭鱼跃、天高任鸟飞,世界大得很!