汇编实现32位无溢出的除法子函数(详细注释)

最近在学习《王爽汇编》,其中一个作业是编写子程序实现除法溢出问题。

描述如下:汇编语言中div可以实现除法,当进行8位除法(被除数16位,除数8位,结果8位)时,商存在al中,余数存在ah中;进行16位除法(被除数32位,除数16位,结果16位,商16位)时,商存在ax中,余数存在dx中。

假设一个16位除法

10000h/1

显然,结果是10000h。可系统默认的16位除法结果是16位的,但在这里10000h显然是溢出的(65536>65535),无法放到一个16位数中。改进策略是拓展结果的长度,也就是当被除数32位,除数16位,令结果为32位,余数是16位

这里需要用到一个公式:

X/N = int(H/N)*65536 + [rem(H/N)*65536+L]/N -----------------------公式①
X:被除数
N:除数
H:被除数X的高16位
L:被除数X的低16位
int()取商
rem()取余数

给出示例参数:

(ax)寄存器储存被除数的低16位 mov ax,4240h
(dx)寄存器储存被除数的高16位 mov dx,000fh
(cx)寄存器储存16位的除数 mov cx,000ah

除法结果的高16位储存在(dx)中,低16位储存在(ax)中,余数储存在(cx)中

自然语言表示就是求0f4240h/000ah的商和余数

思路1(比较巧妙)

仔细观察公式①的第一项:

int(H/N)*65536

int(H/N):被除数的高16位/除数,这里将H拓展为一个32位的数(0000xxxxh),由于其高16位全为0,所以H/N的商一定不会溢出(超过16位)。

那乘以65536应该怎么做呢?我们只需要记得将H/N的商放到一个代表高16位的寄存器中就可以了,并不需要真的乘65536(事实上*10000h也无法简单地用16位乘法实现)。

再看公式②的第二项:

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

rem(H/N)已经在第一项除法中得到了,假设 X = rem(H/N),接下来实现(X+L)/N,显然也是一个32位数/16位数的除法。但这里存在一个问题:如何保证除法的商不会溢出呢?

在这里简单的证明一下**(不想看可以跳过直接看代码)**:

因为 X 是 H/N 的余数,所以 X<=N-1 (X不可能大于N),L是被除数的低16位,不妨令 X=N-1,L=FFFFh。只需证明

[(N-1)|FFFFh]/N<10000h

(((N-1)|FFFFh)以N-1为高16位,以FFFF为低16位。比如N-1 = FFFE,则分子为FFFEFFFFh)。

原式=[(N-1)*65536 + 65535]/N=65536 - 1/N < 10000h

接下来是代码实现(附注释)

assume ds:datasg,ss:stacksg,cs:codesg
datasg segment

datasg ends
stacksg segment
dw 0,0,0,0,0,0,0,0
stacksg ends
codesg segment
start:mov ax,stacksg
		mov ss,ax
		mov sp,16
		mov ax,4240h
		mov dx,000Fh
		mov cx,0Ah
		call divdw
		
		mov ax,4c00h
		int 21h
		;参考公式X/N=int(H/N)*65536+[rem(H/N)*65536+L]/N
		;可以把该32/16位的除法视作2个伪16除法,高位(dx)中存的是0
		;首先000Fh/0Ah,
  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值