|
主题 : : 史上考虑最周全的实验10-3,也是解释最详细的。 [待解决] |
回复[ 12次 ]
点击[ 1006次 ] | |
|
|
|
|
[帖 主]
[ 发表时间:2010-07-27 11:40 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2010-07-11 16:57 |
大家下下来运行下就知道它是最好的了,看看解释就知道它解释的很详细了,再看看代码你就知道它是考虑最周全的了。
如果你觉得对你有益,请回帖,您的回帖将是对我最大的支持。
以下是代码:
;友情提醒:
;这里要提醒各位论坛好友,如果你的程序编译连接都正确,就是运行时出错,请务必认真debug和思考,
;不要动不动就贴到论坛上来问人,不要以为debug是浪费时间,如果你真是一点一滴自己找出来的错误,
;那么这种顿悟会让你永远都不会忘记,你会觉得:纸上得来终觉浅,绝知此事需躬行!
assume cs:code
data segment
db 10 dup(0)
data ends
stack segment
dw 16 dup(0)
stack ends
code segment
start: mov ax,0600h;实验前清屏
mov bh,3ah
mov cx,0000h
mov dx,184fh
int 10h
mov ax,12666
mov dx,0;这里是为了以后扩充,因为以后的数可能超过16位,此时调用实验二的除法
mov bx,data
mov ds,bx
mov bx,stack
mov ss,bx
mov sp,32
mov si,0
call dtoc
mov dh,8
mov dl,3
mov cl,2
call show_str
mov ah,0;等待输入
int 16h
mov ax,0600h;实验后清屏
mov bh,3ah
mov cx,0000h
mov dx,184fh
int 10h
mov ah,0;等待输入
int 16h
mov cx,4c00h
int 21h
show_str: push si
push di
push bx
push ax;所用寄存器全部入栈
mov si,0;这一点非常容易忽视,因为前面赋值时已经将si增长为5了,这里需要重置0
mov ax,0b800h;把显存的段地址赋给es
mov es,ax
mov di,0;变址寄存器赋初值
mov al,0a0h;每行160个字符
mov ah,0;之前ah=0b8,所以在这里将它赋值为0非常必要,也非常容易被忽视
mul dh
mov bx,ax;把行×160的结果存入基址寄存器bx中
add dl,dl;列×2
mov dh,0
add bx,dx;把列导致的位移加入基址寄存器bx中
mov al,cl;转变一下,因为内部要使用cl,所以讲颜色值赋给dl
cycle: mov cl,[si]
mov ch,0
jcxz endup
mov es:[bx][di],cl
mov byte ptr es:[bx][di+1],al
inc di
inc di
inc si
jmp cycle
endup: pop ax
pop bx
pop di
pop si
ret
dtoc: push di
push cx
mov di,0;因为通过余数来求的话,排列结果刚好倒过来了,所以采用栈,di记录进栈多少个数
s2: mov cx,10
call divdw
add cx,30h;余数加上30h变成对应十进制的ASCII值
push cx;进栈保留
inc di;进栈数加1
mov cx,dx;现在dx存储商的高位,ax存储商的低位
jcxz s0
jmp s2;不为0则商不为0,要继续除
s0: mov cx,ax;进一步检查低位是否为0
jcxz s1;如果高位低位都为0,则确定商为0,可以退出本子程序
jmp s2;不为0则商不为0,要继续除
s1: mov cx,di;表示进栈的数,现在用这个数表示循环的次数
s3: pop ax
mov [si],al;对于数字,高8位肯定为0
inc si
loop s3
mov byte ptr[si],0;在最后赋上0
pop cx
pop di
ret
divdw: push bx
;首先计算int(H/N)*65535
push ax;被除数低位入栈
mov ax,dx;用单独的被除数高位dx组成新的被除数
mov dx,0
div cx;求int(H/N)*65536的int(H/N)
push dx;将除得的余数dx入栈
mov bx,ax;商乘上65536就相当于商的结果放到高16位了
;其次,求[rem(H/N)*65536+L]/N
pop dx;将上次除得的余数dx出栈
pop ax;将被除数的低位出栈
;此时的dx和ax分别是即将要被除数的高位和低位了
div cx;计算整体[rem(H/N)*65536+L]/N
;注意,此时dx和ax分别存了后半项的余数和商
mov cx,dx;将余数赋给cx
mov dx,bx;将以前保存在bx中的int(H/N)*65536乘积的高位
pop bx
ret;返回调用程序
code ends
end start
;这个程序我觉得考虑的非常周全,比论坛上其它人做的周全一点,这里不仅仅是12666,这一个简单的5;位,如果是1000000七位数呢?要知道直接除就益处了,所以在这里就直接用了实验2的结果,还有就是在
;显示之前最好清屏,这样有利于观察,大家要养成这个高习惯。 | | |
|
|
|
|
[第1楼]
[ 回复时间:2010-07-27 11:55 ]
[引用]
[回复]
[ top ] | |
荣誉值:268
信誉值:12
注册日期:2010-06-18 22:19 |
|
|
|
|
|
[第2楼]
[ 回复时间:2010-07-27 13:25 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2010-07-11 16:57 |
|
|
|
|
|
[第3楼]
[ 回复时间:2010-08-05 00:19 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2010-07-13 23:22 |
你要知道,书上给你的代码没有定义栈。你并没有根据书本要求来做。如果自己定义一个栈的话,这题就非常好做了。 | | |
|
|
|
|
[第4楼]
[ 回复时间:2010-08-05 08:40 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2010-05-04 17:53 |
|
|
|
|
|
[第5楼]
[ 回复时间:2010-12-13 00:11 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2010-12-04 20:54 |
|
|
|
|
|
[第6楼]
[ 回复时间:2012-09-14 09:34 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2012-08-14 17:57 |
|
|
|
|
|
[第7楼]
[ 回复时间:2012-10-24 16:23 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:2
注册日期:2012-10-18 15:41 |
楼主用了后面学到的知识啊。按部就班应该还没学到终端吧。 | | |
|
|
|
|
[第8楼]
[ 回复时间:2012-10-26 04:12 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2011-08-12 01:04 |
的确是好!
一看就懂!
但是我觉得dtoc子函数不应该调用divdw子函数,如果直接按照16位的除数的除法不是更好! | | |
|
|
|
|
[第9楼]
[ 回复时间:2012-10-26 09:22 ]
[引用]
[回复]
[ top ] | |
荣誉值:30
信誉值:4
注册日期:2012-01-01 16:36 |
回复:[第8楼]
------------------
面对大数据要防止除法溢出。 | | |
|
|
|
|
[第10楼]
[ 回复时间:2013-01-01 20:04 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2013-01-01 17:35 |
正确设置的堆栈段应该不需要程序里写初始化代码,EXE头文件里已经写好相关数据,操作系统装入EXE文件时已经按其头文件的相关数据自动装配好SS和SP,同时从初始化从相应的CS:IP开始执行(如果是DEBUG装入的则不执行但CS、IP也装配好了)
堆栈段的定义
stack segment stack 'stack'
DW 256 DUP(0xFFFFH)
stack ends
这样的堆栈段根本不需要程序里写初始化代码,编译程序会算好并写入文件头,程序载入时会自动初始化装配好的。 | | |
|
|
|
|
[第11楼]
[ 回复时间:2014-11-25 01:18 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2014-11-19 10:35 |
我比较赞同第8楼的说法,用16位作为除数。即使是很大的数据,可以先处理下,再交给dtoc子函数转换。 | | |
|
|
|
|
[第12楼]
[ 回复时间:2021-05-11 17:28 ]
[引用]
[回复]
[ top ] | |
荣誉值:0
信誉值:0
注册日期:2016-03-24 13:33 |
学习了,新手,学了没多久,很多不是太会。多谢分享。 | | |