matlab符号函数的除法,汇编语言IDICV指令:有符号数除法

有符号除法几乎与无符号除法相同,只有一个重要的区别:在执行除法之前,必须对被除数进行符号扩展。

符号扩展是指将一个数的最高位复制到包含该数的变量或寄存器的所有高位中。为了说明为何有此必要,让我们先不这么做。下面的代码使用 MOV 把 -101 赋给 AX,即 DX:AX 的低半部分:

.data

wordVal SWORD -101 ; 009Bh

.code

mov dx, 0

mov ax, wordVal ; DX:AX = 0000009Bh (+155

mov bx, 2 ; BX 是除数

idiv bx ; DX:AX除以BX (有符号操作)

可惜的是,DX:AX 中的 009Bh 并不等于 -101,它等于 +155。因此,除法产生的商为 +77,这不是所期望的结果。而解决该问题的正确方法是使用 CWD( 字转双字 ) 指令,在进行除法之前在 DX:AX 中对 AX 进行符号扩展:

.data

wordVal SWORD -101 ; 009Bh

.code

mov dx, 0

mov ax, wordVal ; DX:AX = 0000009Bh (+155)

cwd ; DX:AX = FFFFFF9Bh (-101 )

mov bx, 2

idiv bx

x86 指令集有几种符号扩展指令。首先了解这些指令,然后再将其应用到有符号除法指令 IDIV 中。

符号扩展指令(CBW、CWD、CDQ)

Intel 提供了三种符号扩展指令:CBW、CWD 和 CDQ。CBW(字节转字)指令将 AL 的符号位扩展到 AH,保留了数据的符号。如下例所示,9Bh(AL 中)和 FF9Bh (AX 中)都等于十进制的 -101:

.data

byteVal SBYTE -101 ; 9Bh

.code

mov al, byteVal ; AL = 9Bh

cbw ; AX = FF9Bh

CWD(字转双字)指令将 AX 的符号位扩展到 DX:

.data

wordVal SWORD -101 ; FF9Bh

.code

mov ax, wordVal ; AX = FF9Bh

cwd ; DX:AX = FFFFFF9Bh

CDQ(双字转四字)指令将 EAX 的符号位扩展到 EDX:

.data

dwordVal SDWORD -101 ; FFFFFF9Bh

.code

mov eax, dwordVal

Cdq ; EDX:EAX = FFFFFFFFFFFFFF9Bh

IDIV 指令

IDIV(有符号除法)指令执行有符号整数除法,其操作数与 DIV 指令相同。执行 8 位除法之前,被除数(AX)必须完成符号扩展。余数的符号总是与被除数相同。

【示例 1】下述指令实现 -48 除以 5。IDIV 执行后,AL 中的商为 -9,AH 中的余数为 -3:

.data

byteVal SBYTE -48 ;D0 十六进制

.code

mov al, byteVal ;被除数的低字节

cbw ;AL扩展到AH

mov bl,+5 ;除数

idiv bl ;AL = -9, AH = -3

下图展示了 AL 是如何通过 CBW 指令符号扩展为 AX 的:

3f6004524707ede70407c6facd7cf901.gif

为了理解被除数的符号扩展为什么这么重要,现在在不进行符号扩展的前提下重复之前的例子。下面的代码将 AH 初始化为 0,这样它就有了确定值,然后没有用 CBW 指令转换被除数就直接进行了除法:

.data

byteVal SBYTE -48 ;D0 十六进制

.code

mov ah, 0 ;被除数高字节

mov al, byteVal ;被除数低字节

mov bl, +5 ;除数

idiv bl ;AL = 41z AH = 3

执行除法之前,AX=00D0h ( 十进制数 208)。 IDIV 把这个数除以 5,生成的商为十进制数 41,余数为3。这显然不是正确答案。

【示例 2】16 位除法要求 AX 符号扩展到 DX。下例执行 -5000 除以 256:

.data

wordVal SWORD -5000

.code

mov ax, wordVal ;被除数的低字

cwd ;AX扩展到DX

mov bx, +256 ;除数

idiv bx ;商 AX=-19,余数 DX=-13 6

【示例 3】32 位除法要求 EAX 符号扩展到 EDX。下例执行 50 000 除以 -256:

.data

dwordVal SDWORD +50000

.code

mov eax, dwordVal ;被除数的低双字

cdq ;EAX 扩展至q EDX

mov ebx, -256 ;除数

idiv ebx ;商 EAX=-195,余数 EDX=+80

执行 DIV 和 IDIV 后,所有算术运算状态标志位的值都不确定。

除法溢出

如果除法操作数生成的商不适合目的操作数,则产生除法溢出 (divide overflow)。这将导致处理器异常并暂停执行当前程序。例如,下面的指令就产生了除法溢出,因为它的商 (100h) 对 8 位的 AL 目标寄存器来说太大了:

mov ax,1000h

mov bl,10h

div bl                   ; AL无法容纳100h

运行这段代码时,Visual Studio 就会产生如下所示的结果错误。如果试图运行除以零的代码,也会显示相同的对话框。

Unhandled exception at 0x00401016 in Project.exe:0xC0000095:Integer overflow.

对此有个建议:使用 32 位除数和 64 位被除数来减少出现除法溢出条件的可能性。如下面的代码所示,除数为 EBX,被除数在 EDX 和 EAX 组成的 64 位寄存器对中:

mov eax,1000h

cdq

mov ebx,10h

div ebx               ; EAX = 00000100h

要预防除以零的操作,则在进行除法之前检查除数:

mov ax, dividend

mov bl, divisor

cmp bl, 0 ;检查除数

je NoDivideZero ;为零?显不错误

div bl ;不为零:继续

.

.

NoDivideZero: ;显示 "Attmpt to divide by zero"

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值