. : : Assembly Language : : .  |  首页  |  我提出的问题  |  我参与的问题  |  我的收藏  |  消息中心   |  游客  登录  | 
刷新 | 提问 | 未解决 | 已解决 | 精华区 | 搜索 |
  《汇编语言》论坛 ->CALL和RET指令
  管理员: assembly   [回复本贴] [收藏本贴] [管理本贴] [关闭窗口]
主题 : :  实验10   子程序2解决除法溢出问题      问题多多,请大虾指点!  [已解决] 回复[ 5次 ]   点击[ 402次 ]  
abcdwzxy
[帖 主]   [ 发表时间:2009-05-18 21:05 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:3
注册日期:2009-03-13 16:19
根据公式:    X/N=INT(H/N)*65536+[REM(H/N)*65536+L]/N
                H=INT(X/65536);L=REM(X/65536)

我的程序是这样的:
assume
  data segment
     dw 0000000
  data ends
  code segment
   start:mov ax,data
         mov ds,ax
         mov ax,4240H
         mov dx,000fH     '设置被除数'
         mov cx,0aH       '设置除数'
         call divdw
         mov ax,4c00H
         int 21H
         
    divdw:mov bx,65536
          div bx          '计算X/65536,AX中放商(既公式中的H),DX中放余数(既公式中的L)'
          mov ds:[0],ax   '将H放在DS:[0]内存单元'
          mov ds:[2],dx   '将L放在DS:[2]内存单元'

          mov dx,0        '设置被除数,DX=0 高16位,AX低16位为H'
          div cx          '计算H/N,除数在CX中,计算后AX中为H/N的商,DX中为H/N的余数'
          
          mov ds:[4],ax   '将H/N的商放在DS:[4]内存单元'
          mov ds:[6],dx   '将H/N的余数放在DS:[6]内存单元'

          mul bx          '计算INT(H/N)*65536,结果的高16位放在DX中,低16位放在AX中'
  
          mov ds:[8],dx   '将INT(H/N)*65536结果的高16位放在DS:[8]内存单元'
          mov ds:[a],ax   '将INT(H/N)*65536结果的低16位放在DS:[A]内存单元'

          mov ax,ds:[6]   '将DS:[6]内存单元中的H/N的余数取出放在AX中'

          mul bx          '计算REM(H/N)*65536,结果的高16位放在DX中,低16位放在AX中'
 
          mov ds:[c],dx   '将REM(H/N)*65536结果的高16位放入DS:[C]内存单元'
          mov ds:[e],ax   '将REM(H/N)*65536结果的低16位放入DS:[E]内存单元'

          add ax,ds:[2]   '将REM(H/N)*65536与L相加,结果放在AX中'
          mov ds:[e],ax
           
          div cx          '计算[REM(H/N)*65536+L]/N'
 
          mov cx,dx       '结果的余数放入CX中'
          add ax,ds:[a]   'AX中放入结果的低16位'
          mov dx,ds:[8]   'DX中放入结果的高16位'
          ret
code ends
end start

这个程序我编译和连接都通过了,但是用DEBUG跟踪是会出现问题,得不到预想中的结果;
我分析了一下,在这个程序执行过中,
在  add ax,ds:[2]这条指令执行是参生了加法溢出,既REM(H/N)*65536与L相加后会参生溢出的情况(用DEBUG跟踪是看到的),但是附注的公式证明却证明了不会参生溢出情况;

还有一个问题是公式中的那个数65536  我觉得有点问题,65536刚好大于65535(FFFFH)既在BX中放不下;


请教各位该问题该如何解决啊  谢谢!!
zhenglxd
[第1楼]   [ 回复时间:2009-05-21 13:51 ]   [引用]   [回复]   [ top ] 
荣誉值:30
信誉值:0
注册日期:2009-04-09 10:05
你这个可怜的babby
不要死套公式啦

不过这个东西解释起来超级麻烦。。。
我试着解释下!

防溢出关键 就是将一个会溢出的除法 分成若干个不会溢出的除法来做
就本题的范围防止的溢出 是防止寄存器的值超过寄存器限制
我们知道就本题的范围来说 什么样的情况会溢出? 因为 除数的范围是 1~ffff 而被除数的范围是
无限的 如果除数过小 比如=1 而被除法=1百万 那么自然会溢出了,不仅是被除数溢出而且也是结果溢出
那么怎么让他不溢出呢?将一个会溢出的除法 编程多次不会溢出的除法来做

1百万/1 = 50万/1+50万/1=10万/1*10。。。 依次类退

这个仅仅是思路在汇编中 具体就是 不同的被除数位数和除数分别除法

高位被除数 和除数如果有商 那么这个结果 一定是除法的最终结果的高位(将商保存)
如果没有那么必定会有余数,余数就被作为低位被除数的高为然后在进行除法
得出的结果加上最高为的商 就是最终结果
实际上对于一个非常大的数字高位来说 如果他和被除数有商 那么这个商 只能放在结果的高位中,(因为转换到低位的话 16位寄存器会放不下) 不管这个结果是几,他反正是最终的结果的最高位
而他如果有余数那么余数肯定不能丢弃啊 所以余数作为 低位数的高位来进行除法
#######################################################
就好比 10万零1 除以 10    我的寄存器只能存放 10万怎么办? 因为被除数超过寄存器所以
高位为 0001 低位为0

做除法时候 1/10 余下1 那么最终最高位结果为0 余下的1 跑到低位的除法高位数中
这样就成了一个普通的 16位被除数除法了
abcdwzxy
[第2楼]   [ 回复时间:2009-05-22 11:38 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:3
注册日期:2009-03-13 16:19
先谢谢你的解释哈,可能是因为这个东西太抽象了吧,我看得不是很懂耶~~
不过还是谢谢你了哈!
zhenglxd
[第3楼]   [ 回复时间:2009-05-22 16:55 ]   [引用]   [回复]   [ top ] 
荣誉值:30
信誉值:0
注册日期:2009-04-09 10:05
回复:[第2楼]
------------------
好吧!我再尝试着用不抽象的解释下!

内存中一段数据(0~6表示地址!)像 256这个数值在内存中是如下的显示的:

0    1     2     3     4     5      6
00   00    01

很明显一个字节内存单元只能储存的数据是0~255, 注意看 地址2 他表示这个数据的高位,他其下的值就是所谓高位的值,而地址0和1就储存着低位的值
也就是说一个数据如果过大 结果会导致这个数据占用多个内存单元,因为每个内存单元的储存的值都是有限的
规则就是高位 的地址存放 高位的值 低位的地址存放低位的值,所以只要你的内存够大,对于一个数据而言,他永远都不愁在内存中放不下

除法的关键是 溢出 溢出就是 数值超过寄存器存放的上限,怎么办呢?
那么,一个被除数的高位地址下的数据 和低位地址下的数据 他们分开来做除法,如果一个被除数 在内存中是 类似 10000H这样的值 我们就无法拿他去除法了 因为寄存器放不下,那么我们通过把这个值分开来进行除法来求的不会溢出的值

首先要知道的是 8086规定 在做除法的时候 被除数是16位 那么ax存放值  dx存放余数
那么 如果除数过小比如1 ,而被除数比如10000H 那么做出来的结果一定溢出。
所以我们分开来做,要确定你的除法不溢出 那么 我们要做的就是 把会溢出的部分 和不会溢出的部分分别来做除法

例如 10000H 除以1 10000H 在内存中 他的高位地址对应的数据是 1 低位地址的数据是0000如下
0   1   2    3   4   5   6 
00  00  00   00  01

如果你用ax放他的低位地址数据(0000) 用dx放他的高位地址数据(1)那么结果会超值

从他的地址来看我们知道 01这部分会溢出
那么我们先用01 这部分去做除法 1/1 =1 这个结果1 代表高位除法的结果,所以这个结果在内存地址中的位数 一定是总结果中 最高的(我们保存这个值)
然后再用0去和1做除法 然后结果也是0 所以最终 按照位数把他们在内中排号 就是
0   1   2    3   4   5   6 
00  00  00   00  01
所以这样做永远不会溢出我们要做的仅仅是转移高位的商到他相应的位数上

再举个列子 10000 /3
高位 为1 低位为0 除数是3
高位除法1和3 除不仅 会有余数,如果高位除法有商那么商就是结果的高位值得,如果会有余数 ,那么余数自然不能丢弃,余数就作为 低位除法的 dx(也就是高位的被除数,因为他是从高位除法中余下的)
之后做低位除法的时候 就拿 余下的dx+ 低位数的ax除以3 会得到 一个低位的商 和 余数
高位的商+低位数的商+余数 就是结果

其实原理就是 如果一个 数值 寄存器放不下 那么高位地址 和 除数做除法 如果有商 那么这个商寄存器也肯定是放不下的 (因为高位结果的商 哪怕是1 实际代表是的数值 = ffff+1)所以我们转移走他把它 安排到 除法总结果的 高位地址上 好比ffff+1 =10000H 实际上这个1 就是ffff+1他的 位地址是最高位的 明白了点不?

继续 如果高位地址有余数 那么这个余数的值不能丢弃因为他是高位值的余数自动转为低位值的高位被除数并且 和 低位地址的被除数 在和除数做除法 必然不会溢出,因为  高位除法的余数 他的范围是0~ffff 所以就算除以1 也最多等于ffff

原理就是 对于16位除数的除法 如果 他会溢出 结果只可能是因为 高位地址的值溢出,所以如果高位地址的值和除数 做完除法 那么如果有商 这个商就是会溢出的值 你保存好 如果有余数 那表示 余数在这参加 低位值除法的时候一定不会溢出了 因为该溢出的部分已经被转移走了

这就好比我说的 把一个会溢出的除法 变成几个除法来做!
abcdwzxy
[第4楼]   [ 回复时间:2009-05-23 13:59 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:3
注册日期:2009-03-13 16:19
谢谢你的回答,让我有了进一步的理解!
谢谢!!
abcdwzxy
[第5楼]   [ 回复时间:2009-06-22 02:29 ]   [引用]   [回复]   [ top ] 
荣誉值:0
信誉值:3
注册日期:2009-03-13 16:19
此贴由 贴主 于 [ 2009-06-22 02:29 ] 结贴。 结贴原因:问题已解决
得分情况: 1楼(zhenglxd):4分   3楼(zhenglxd):4分  
此问题已结贴!
    Copyright © 2006-2024   ASMEDU.NET  All Rights Reserved