汇编网首页登录博客注册
unixandlinux的学习博客
博客首页博客互动【做检测题】论坛求助

我的博客

个人首页 |  我的文章 |  我的相册 |  我的好友 |  最新访客 |  文章收藏 |  论坛提问 |  友情链接 |  给我留言  
图片载入中
学习动态
最新评论
最新留言
好友圈
友情链接

[2023-04-28 17:12] 第5章 问题 5.3

问题 5.3

改进“问题 5.2”中的程序代码,提高 123*236 的计算速度。书本思路:将 123*236 的乘数和被乘数颠倒。
基于书本的思路,可以有更快的计算速度:除颠倒乘数和被乘数位置而变成 236*123 外,可以使用将式子变换为 236*2ⁿ,再将乘数 123 与 2ⁿ 进行迭代比较,使两者不断接近直至达到两者之差最小(0、1 或 -1),然后对计算结果进行适当修正(如果需要的话)以使两者完全相等。
236*2ⁿ 可以通过 loop 循环的方法来实现:
mov ax,236
s:        add ax,ax
...
        loop s
        
程序代码如下(以 236*3、236*4、236*5、236*6、236*7 来心算测试):
assume cs:code
code segment

        mov cx,3000h  ; 如果省略设置 SS、SP 寄存器存储的数据的代码,则默认将使用系统自动分配的栈空间
        mov ss,cx
        mov sp,0
        mov cx,1000h
        mov ds,cx
        mov cx,123
        mov bx,0
        mov [bx],cx  ; 将允许执行的循环临界值数据 123 存入 [1000:0000] 地址字单元。

u:        mov ax,236
        mov dx,2
s:
; 将存储在 [1000:0000] 的允许执行循环的临界值减去本次循环的 2ⁿ⁻¹,差值结果存入 [1000:0002]
; 当 (1000:0000) 为偶数时,最终 (1000:0002)==0;当 (1000:0000) 为奇数时,最终 (1000:0002)==-1
; 当 (1000:0002)==-1 时,说明多加了一次被乘数 236,因此需要对此作出处理
        mov bx,0
        mov cx,[bx]
        sub cx,dx
        mov bx,2
        mov [bx],cx  ; 将 CX 寄存器中存储的数据存入 [1000:0002] 字单元

; 将 [1000:0000] 单元中的循环临界值数据存入 BX 寄存器
        mov bx,0
        mov cx,[bx]
        mov bx,cx

        mov cx,2
        add ax,ax  ; 执行 (ax)=(ax)*2ⁿ⁻¹(n≥2)
        add dx,dx  ; 将 2ⁿ 存入 DX 寄存器(n≥2)
        sub bx,dx  ; 当 2ⁿ≤(bx) 时,(bx)=(bx)-(dx)≥0,所以 (bh)==0(高 8 位为 00H)
; 当 2ⁿ>(bx) 时,(bx)=(bx)-(dx)<0,所以 (bh)==-1(高 8 位为 FFH)
        add cl,bh  ; 当 (bh)==0 时,(cl)=(cl)+(bh)=2+0=2,即 (cx)==2
; 当 (bh)==-1 时 (cl)=(cl)+(bh)=2-1=1,即 (cx)==1
        loop s  ; 执行 (cx)=(cx)-1

; 跳出 s 标号循环后,(cx)==0,(bh)==-1
        push ax  ; 将 236*2ⁿ⁻¹ 的计算结果入栈。
; 将 [1000:0002] 中存储的数据存入 CX 寄存器
        mov bx,2
        mov cx,[bx]
; 修正执行循环的临界值
; 将 CX 寄存器的低 8 位减去高 8 位后的计算结果存入其低 8 位单元
; 目的是,当 (10002)==-1(FFH)时,使 (cx)==0;当 (cx)!=-1 时,保持 CX 寄存器存储的数据不变
; —— 其高 8 位必全为 0,因此低 8 位减高 8 位后,(cx) 不会改变
        sub cl,ch  ; 执行 (cl)=(cl)-(ch)
        mov ch,0  ; 当 (cx)==-1 时,sub cl,ch 只令 (cl)==0,并未令 (ch)==0,因此需要添加本行代码
; 当 (cx)!=-1 时,(ch)==0,因此执行本行代码不会改变 (ch)。
        mov bx,0
        mov [bx],cx  ; 将 CX 寄存器中存储的循环临界值数据存入 [1000:0000] 地址字单元。
        inc cx
        loop u

; 将栈中的数据累加到 DX 寄存器中
        mov dx,0
v:        pop ax
        add dx,ax
        mov cx,sp
        inc cx
        loop v

; 处理 (10002)==-1 时,多加了一次被乘数 236 的情况
; 最终的计算结果将存储在 DX 寄存器中
        mov ax,0
        mov bx,2
        mov cx,[bx]  ; 将 (10002) 存入 CX 寄存器
        mov bx,ax  ; (bx)==0
t:        sub dx,ax  ; 首次,(dx)=(dx)-(ax)=(dx)-0;第 2 次,(dx)=(dx)-(ax)=(dx)-236
        mov ax,236
        add bx,1  ; 首次,(bx)=0+1=1;第 2 次,(bx)=1+1=2
        add cx,bx  ; 如果 (10002)==0,则首次执行指令后,(cx)=0+1=1,执行 loop:(cx)=(cx)-1=0
; 如果 (10002)==-1,则首次执行指令后,(cx)=-1+1=0,执行 loop:(cx)=(cx)-1=-1
; 第 2 次,(cx)=-1+2=1,执行 loop:(cx)=(cx)-1=0
        loop t
; 将计算的最终结果存入指定内存单元,方便程序执行完毕后查看验证
        mov cx,2000h
        mov ds,cx
        mov bx,2    
        mov [bx],dx

        mov ax,4c00h
        int 21h

code ends
end

说明:将上面的程序代码保存为 q5_3.asm 文本文件,用第 4 章所述方法对该汇编源程序文件进行编译、链接后,即生成可执行文件 q5_3.exe。
由于程序末尾将 236*123 的计算最终结果存储到内存单元 [2000:0002] 中,因此在执行 q5_3.exe 前应该先用 Debug 查看该内存单元所存储的数据内容,再退出 Debug,然后运行 q5_3.exe,最后再用 Debug 查看同一内存单元所存储的数据的变化情况,即可验证程序运行的结果是否正确。
另外,为验证程序是否健壮,可以将被乘数 123 换成一个偶数,例如 122,即计算 236*122,编译、链接后,用同样的方法验证之。
评论次数(0)  |  浏览次数(113)  |  类型(问题分析) |  收藏此文  | 
 
 请输入验证码  (提示:点击验证码输入框,以获取验证码