曲曲的秘密学术基地

纯化欲望、坚持严肃性

欢迎!我是曲泽慧(@zququ),目前在深圳(ICBI,BCBDI,SIAT)任职助理研究员。


病毒学、免疫学及结构生物学背景,可以在 RG 上找到我已发表的论文

本站自2019年7月已访问web counter

汇编语言 实验10 (2) 解决除法溢出的问题

div 复习

div指令可以做除法。当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;进行16位除法的时候,用ax存储结果的商,dx存储结果的余数,

数据类型 寄存器 存放内容
8位 al
  ah 余数
16位 ax
  dx 余数

可是,现在有一个问题,如果结果的商大于al或ax的所能存储的最大值,将如何?

如下,进行的是8位除法,结果的商为1000,而1000在al中放不下。

mov bh, 1
mov ax, 1000
div bh

又如,进行的是16位除法,结果的商为11000H,而11000H在ax中存放不下。

mov ax, 1000H
mov dx, 1
mov bx, 1
div bx

当结果的商过大,超出了寄存器所能存储的范围。当CPU执行div等除法指令的时候,如果发生这样的情况,将引发CPU的一个内部错误,这个错误被称为:除法溢出。我们可以通过特殊的程序来处理这个错误。

所以,由于有这样的问题,我们再进行除法运算的时候要注意除数和被除数的值,比如1000000/10就不能用div指令来执行计算。

问题

设计子程序,

名称:divdw

功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。

参数:

(ax) = dword型数据的低16位,
(dx) = dword型数据的高16位,
(cx) = 除数

返回:

(ax) = 结果的低16位,
(dx) = 结果的高16位,
(cx) = 余数

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

mov ax, 4240H
mov dx, 000FH
mov cx, 0AH
call divdw

结果:

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

提示:

给出一个公式:

X:被除数,范围:[0, FFFFFFFF]
N:除数,范围:[0, FFFF]
H:X高16位,范围:[0, FFFF]
L:X低16位,范围:[0, FFFF]
int():描述性运算符,取商,比如,int(38/10)=3
rem():描述性运算符,取余数,比如,rem(38/10)=8

公式:X/N = int(H/N)*65536+[rem(H/N)*65536+L]/N

关于公式的详细解析:

X/N代表着目标可能会存在溢出问题的除法,可以被分解为两个因式。第一个分式,int(H/N)意味着X的高16位与除数之间的除法后的商,由于本身是高16位所以要乘以一个65526($2^{16}$)系数,这个时候同样会产生一个余数,即位rem(H/N),同样的也要乘以65526并加X的低16位,并将二者相加除以除数N。最终再将高位的商与低位(高位余数与低位的和)的商相加即为X/N的商,而低位的余数即位X/N的余数。

这个公式将可能产生溢出的除法运算:X/N,转变为多个不会产生溢出的除法运算。公式中,等号右边的所有除法运算都可以用div指令来做,肯定不会导致除法溢出。

代码,

start: mov ax, 4240H
       mov dx, 000F
       mov cx, 0AH
       call divdw

divdw: push si
       push bx
       push ax

       mov ax, dx
       mov dx, 0  ;dx寄存器清零,用于稍后存放余数
       div cx  ;执行int(H/N)*65536,高16位的商在ax,余数在dx
       mov si, ax  ;将高16位商存放在si
       pop ax    ;低位被除数出栈
       div cx  ;此时,ax中是低位被除数,dx中存放高位除法余数,
               ;所以这里执行的即:[rem(H/N)*65536+L]/N
               ;低位的商在ax,低位的余数在dx
       mov cx, dx   ;低位的余数即为最终的余数
       mov dx, si   ;高位的商即为最终的商的高位

       pop bx
       pop si
       ret

code ends
end start

公式防溢出的证明

1.(X/N) = (H*65536)/N + (L/N)
2.(X/N) = [int(H/N) + rem(H/N)]*65536/N + (L/N)
3.(X/N) = int(H/N)*65536 + [rem(H/N)*65536 + L]/N
由3可知,高16位除法的商即为最终的高16位商

本实验共执行了两次除法,

第一次,H/N 的二次,[rem(H/N)*65536 + L]/N

因为H ≤ 65535,所以H/N不会溢出

1.L ≤ 65535
2.rem(H/N) ≤ (N-1)
由2得,
3.rem(H/N)*65536 ≤ (N-1)*65536
由1,3有,
4.rem(H/N)*65536+L ≤ (N-1)*65536 + 65535
5.[rem(H/N)*65536+L]/N ≤ [(N-1)*65536 + 65535]/N
6.[rem(H/N)*65536+L]/N ≤ [65536-(1/N)]

所以不会发生溢出。

Last One

汇编语言 寄存器总结 (转载)

转自CSDN博客,Dask Jhonson转自CSDN博客,iteye_10501表格总结: 寄存器的分类   寄存器 主要用途 通用寄存器 数据寄存器 AX 乘、除运算,字的输入输出,中间结果的缓存     AL 字节的乘、除运算,字节的输入输出,十进制算数运算     A...…

汇编语言More
Next One

python 魔法方法 (6) 描述符,property()函数的原理

整理自小甲鱼鱼C论坛描述符的概念描述符就是将某种特殊类型的类的实例指派给另一个类的属性。而这个特殊类型的类,就是至少要再这个类里面定义__get__()、__set__()或__delete__()三个特殊方法中的任意一个。 魔法方法 含义 __get__(self, instance, owner) 用于访问属性,它返回属性的值 __set__(self, instance, value...…

pythonMore