简介 :
设计一个不会产生溢出的除法运算
1. 被除数 32 字节
2. 除数 16 字节
3. 商 32 字节
4. 余数 16 字节
代码 :
assume cs:code,ds:data,ss:stack
data segment
data ends
stack segment
db 16 dup(0)
stack ends
code segment
start:
; 设置被除数
mov dx, 1234H
mov ax, 5679H
; 设置除数
mov bx, 0004H
; 调用函数
call divdw
; 程序返回
jmp finish
; 功能 : 不会产生溢出的 divdw 函数
; 参数 :
; 被除数 : dx 高 16 位 , ax 低 16 位
; 除数 : bx
; 返回 :
; 商 : dx 高 16 位 , ax 低 16 位
; 余数 : cx
; 公式 :
; X / n -> 商 S(32bit) 余 Y(16bit)
; X = H * 65536 + L
; S_H = H / n
; S_L = (rem(H / n) * 65536 + L) / n
; 上一行公式的商为最终结果的低 16 位 , 余数即为最终的余数
divdw:
; 首先计算商的高 16 位
; 注意这里我们的除数是 16 位的
; 如果进行 div 运算的时候默认会将被除数当成 32 位
; 其中高 16 位在 dx 中 , 低 16 位在 ax 中
; 因此首先要将 ax 的值保存起来 , 然后将 dx 的值移动到 ax 中
; 然后将 dx 清零 , 计算完成后还要恢复 ax
push ax
mov ax, dx
xor dx, dx
div bx ; 进行除法运算 , ( ax 保存商 , dx 保存余数 )
; 我们接下来要使用上一个除法运算得到的余数
; 除法运算需要使用 ax , 但是现在 ax 保存着商
; 因此我们需要将 ax 再进行保存
; 这里先使用一个暂时不用的寄存器进行保存 , (si)
mov si, ax ; 将商保存
; 现在 dx 中存放的是被除数高 8 位除以除数得到的余数
; 根据公式 , 下一次的除法运算
; 要将第一次的除法运算的商左移 16 位在加上被除数的低 16 位作为新的被除数
; 但是我们知道 , 在 div 指令中 , 32 位的除法
; 刚好是 dx 中存放高 16 位 , ax 中存放低 16 位 , 因此直接进行除法运算即可
pop ax ; 设置新的被除数的低 16 位 , 也就是旧的被除数的低 16 位数
div bx ; 进行除法运算
; 商保存在 ax 中 , 余数保存在 dx 中
; 这个时候得到的余数就是真正的余数
; 商 就是真正的商的低 16 位 , 而真正的商的高 16 位被我们临时保存在了 si 中
; 现在我们需要将余数存在 cx 中 , 商的高 16 位存在 dx 中 , 然后就可以返回了
mov cx, dx
mov dx, si
ret
finish:
mov ax,4cH
int 21H
code ends
end start