除法(DIV/IDIV)
DIV
(unsigned divide)无符号数除法
格式:DIV SRC
操作:
- S R C SRC SRC为字节时, ( A L ) ← ( A X ) / ( S R C ) (AL)\gets (AX)/(SRC) (AL)←(AX)/(SRC)的商, ( A H ) ← ( A X ) / ( S R C ) (AH)\gets (AX)/(SRC) (AH)←(AX)/(SRC)的余数
- S R C SRC SRC为字时, ( A X ) ← ( D X , A X ) / ( S R C ) (AX)\gets (DX,AX)/(SRC) (AX)←(DX,AX)/(SRC)的商, ( D X ) ← ( D X , A X ) / ( S R C ) (DX)\gets (DX,AX)/(SRC) (DX)←(DX,AX)/(SRC)的余数
该指令将参与运算的数据默认为无符号数,则商和余数都是无符号数
除法貌似并不会影响标志位(进位标志 C F CF CF和溢出标志 O F OF OF)的改变,但通过上述操作可知,被除数位数总是除数的两倍,而相除的商和余数是存储在和除数位数相同的空间里,显然余数是肯定够存的,但是商是有可能存不下的(例如: 0300 H ÷ 02 H = 0180 H 0300H\div 02H=0180H 0300H÷02H=0180H,这里商仅依靠字节存储是无法存下的)。商出现溢出时,系统转0号类型中断处理,提示“divide overflow”,并退出程序,返回到操作系统,程序便已经崩溃了。要想避免出现这种情况,必须在作除法前对溢出作出预判
由于商需要更大空间来存储,而字节长度的除数无法满足,因此需要将其扩展为字长度,这样商便有了字长度空间存储
MOV AX, 300H
CWD ;这里书上使用CWD指令进行字到双字的符号扩展(将AX的符号位即最高位填充至DX的所有位),而这里使用的是无符号数除法,当被除数的最高位为1时显然会扩大被除数的大小,我认为应当使用零扩展(即将DX所有位置0),这样便不会改变原数的大小,但我未查询到汇编零扩展的相关指令,或许没有该指令,也许只能自己手动零扩展(MOV DX, 0)
MOV BX, 2
DIV BX ;这里的SRC为字长
这里使用CWD
进行符号扩展是因为
S
R
C
SRC
SRC为字长时,被除数则为
(
D
X
,
A
X
)
(DX,AX)
(DX,AX),因此需将这两寄存器一起看作被除数,于是使用CWD
将
D
X
DX
DX置0,使其整体等于
300
H
300H
300H,这里个人认为因采用类似MOV DX, 0
的指令去处理更为合理
等到的结果商为 180 H ( A X ) 180H(AX) 180H(AX),余数为 0 H ( D X ) 0H(DX) 0H(DX)
IDIV
(signed divide)有符号数除法
指令格式和操作与无符号数除法相同,用来作有符号数除法。最终商的符号应是两个操作数符号的异或,而余数的符号和被除数符号一致
这里用 F F 80 H ( − 128 ) ÷ 03 H ( + 3 ) = D 6 H ( − 42 ) ⋯ ⋯ F E H ( − 2 ) FF80H(-128)\div 03H(+3)=D6H(-42)\cdots \cdots FEH(-2) FF80H(−128)÷03H(+3)=D6H(−42)⋯⋯FEH(−2)举例