7.36 王爽汇编语言(三十三)
实验 10 编写子程序
(2): 解析:首先复习一下 div 指令,在书 P169
div 是除法指令,格式:div reg 或 div 内存单元
其中除数:有 8 位和 16 位两种,即在上述表达式 div 指令后头;
另外针对被除数、商、余数:
1.如果除数为 8 位,则被除数为 16 位,默认存放在 AX 中;
另外 AL 存储除法操作的商,AH 存储除法操作的余数。
2.如果除数为 16 位,则被除数为 32 位,默认存放在 DX 和 AX 寄存器中,其中 DX 存放高
16位,AX 存放低 16 位。
另外 AX 存储除法操作的商,DX 存储除法操作的余数。
另外我们看应用举例中,是把商保存到了两个 16 位寄存器中,这样也许就不会溢出了。(因为我们单纯做 16 位除法的时候,只有一个寄存器 AX 会用来保存商,这可能会导致结果溢出的问题)
然后题目中给出了结果不会溢出的计算公式如下:
# X 代表被除数,N 代表除数,H 代表被除数 X 的高 16 位,L 代表被除数 X 的低 16 位
X/N = int(H / N) * 65536 + [rem(H / N) * 65536 + L]/N
# 其中 int() 描述符:
int(38 / 10) = 3,即取商的意思
# 其中 rem() 描述符:
rem(38 / 10) = 8,即取余数的意思
另外还要复习一下 mul 指令对于 16 位乘法的计算方式:
# 格式如下:
mul reg 或 mul 内存单元
# 16 位乘法
一个默认存放在 AX 寄存器中,另一个即在上述 mul 指令后头
结果高位存放在 DX 中,低位存放在 AX 中
参考小甲鱼后独立完成的示例程序如下: 参考链接:https://www.bilibili.com/video/BV1Rs411c7HG?p=52
; 不会溢出的除法函数(子程序)
; 公式:X / N =
; X 代表被除数,N 代表除数,H 代表被除数 X 的高 16 位,L 代表被除数 X 的低 16 位
; X/N = int(H / N) * 65536 + [rem(H / N) * 65536 + L]/N
; 其中 int() 描述符:
; int(38 / 10) = 3,即取商的意思
; 其中 rem() 描述符:
; rem(38 / 10) = 8,即取余数的意思
; 其中被除数为 dword 型,除数是 word 型,结果为 dword 型
assume cs:code, ss:stack
stack segment
dw 8 dup(0)
stack ends
code segment
main:
mov ax, stack
mov ss, ax
mov sp, 10h ; 初始化栈段
mov ax, 4240h ; ax 保存被除数的低 16 位
mov dx, 000fh ; dx 保存被除数的高 16 位
mov cx, 0ah ; cx 保存除数
call divdw ; 调用 divdw 子程序进行计算
mov ax, 4c00h
int 21h
divdw:
push ax ; 将低 16 位保存起来
mov ax, dx ; 将高 16 位放到 ax 寄存器,方便后续 16 位除法
mov dx, 0 ; 16 位除法(即除数为 16 位时),被除数需要为 32 位,然后被除数高位存放在 dx
div cx ; int(H/N) 保存在 AX 中,rem(H/N) 保存在 DX 中
mov bx, ax ; 用 bx 暂存我们的商
pop ax ; 将被除数低 16 位从栈中弹出到 AX 寄存器
div cx ; [rem(H/N)*65536 + L]/N,巧妙之处在于我们的 rem(H/N)*65536 就已经在 DX 寄存器中了
mov dx, bx ; 存放到 dx 寄存器
mov cx, dx ; 余数保存到 cx 中
; 另外 div cx 的商结果已经在 ax 寄存器中了,也就是说满足结果的 低 16 位保存在 ax 寄存器中
ret ; 返回到主程序调用处
code ends
end main
上述程序其实用不到 mul 指令,因为你要明白 N*65536 ,等价于 N 左移 16 位,自然 N 就到高位了。然后明白其公式的原理,就会了。
总结
最近做这些题,自己学习的进度看起来明显变慢了,不过只要慢慢来就好了,不用管其它。加油! 图书馆奋战的一天!