用汇编语言计算N阶乘0到FFFFH.docx
《用汇编语言计算N阶乘0到FFFFH.docx》由会员分享,可在线阅读,更多相关《用汇编语言计算N阶乘0到FFFFH.docx(18页珍藏版)》请在冰豆网上搜索。
用汇编语言计算N阶乘0到FFFFH
一、设计题目
编写计算N!
的程序(数值N由键盘输入,结果在屏幕上输出。
N的围为0-65535,即刚好能被一个16位寄存器容纳)。
二、开发目的
由于当N值较大时(N>10),N的阶乘计算很繁琐并且计算容易出错。
所以可以编写计算N!
的程序,利用计算机强大的计算能力计算N!
。
这不仅能节省繁琐计算的时间,而且得到的N!
的积比起手工算的要准确。
三、设计方案
N的阶乘为1*2*3……(N-1)*N,N的围为(0000H—FFFFH),N!
以字为单位存在一个或几个定义的数据段中。
若已算到(n-1)!
,假如它占4个字的空间,接下来它乘以n的原理,如图1所示。
图1(n-1)!
*n的原理
因此计算N!
的算法可以这样编写,当前n!
的值为被乘数,容存在str2中,单位为字,n+1的值为乘数,存在str1中,单位也为字。
被乘数从str2首地址中容开始与乘数相乘,得到32位的积,它的低16位覆盖掉当前被乘数所在存储空间的容。
接着str2下一个字的容与乘数相乘,也得到32位的积,前一个积的高16位与现在积的低16位相加,它们的和覆盖掉当前被乘数所在存储空间的容,若它们的和有进位,把进位加到现在积的高16位。
直到把str2中容乘完。
然后乘数增1,循环上面的容。
直到执行完(N-1)!
*N
输入的N为4位16进制数,输出也为16进制数。
四、程序流程图
Y
N
Y
N
Y
N
N
N
Y
Y
结束
五、程序清单
data1segment
input1db'pleaseinputthenumber:
','$'
input2db10,?
10dup(?
);输入的16进制数
errordb'Outofrange','$'
output1db'Theansweris1','$'
output2db'Theansweris:
','$'
str1dw100dup(?
);保存1—N(后一个数覆盖前一个数)
str2dw7000hdup(?
);N!
乘积的值
(1)
pdw100dup(?
);上一个乘积的高16位
data1ends
data2segment
str3dw7fffhdup(?
);N!
乘积的值
(2)
data2ends
codesegment
assumecs:
code,ds:
data1,es:
data2
org100h;程序从偏移地址100h开始执行
start:
movax,data1;程序初始化
movds,ax
movax,data2
moves,ax;初始化结束
movah,9
leadx,input1
int21h
movah,2;回车
movdl,0dh
int21h
movah,2;换行
movdl,0ah
int21h
movah,0ah;输入所需求的N值(N为16进制数)
leadx,input2
int21h
movah,2
movdl,0dh
int21h
movah,2
movdl,0ah
int21h
leabx,input2
moval,[bx+1];判断输入的N值是否超过FFFFH
cmpal,4
jas1
movcl,4;把输入的N值有ASCH码转成16进制数
movah,[bx+2]
moval,[bx+3]
cmpal,39h
jaabc1
def1:
shlal,cl
cmpah,39h
jaabc2
def2:
shrax,cl
movdh,al
movah,[bx+4]
moval,[bx+5]
cmpal,39h
jaabc3
movcl,4
def3:
shlal,cl
cmpah,39h
jaabc4
def4:
shrax,cl
movdl,al;转换结束
movax,dx;判断N值是否为0
cmpax,0
jzs2
jmps3
abc1:
subal,37h
jmpdef1
abc2:
subah,37h
jmpdef2
abc3:
subal,37h
jmpdef3
abc4:
subah,37h
jmpdef4
s1:
movah,9;若N值超过FFFFH的输出
leadx,error
int21h
jmpnext
s2:
movah,9;N值为1的输出
leadx,output1
int21h
jmpnext
s3:
movcx,ax;计算N的阶乘
movax,1
mov[str1],ax;N从1开始,作为乘数
leasi,str2
mov[si],ax;N!
的积从1开始,作为被乘数
movax,0
mov[p],ax;(n-1)!
的乘积的低16位与n相乘后积的高16位
movbx,1;开始N!
的乘积占一个字空间
movWORDptr[p+10],0;(n-1)!
的乘积的高16位与n相乘后积的低16位和(n-1)!
的乘积的低16位与n相乘后积的高16位的和的进位,初始进位为0
movah,9
leadx,output2
int21h
movah,2
movdl,0dh
int21h
movah,2
movdl,0ah
int21h
lop2:
mov[p+2],bx
lop3:
movax,[si];(n-1)!
的乘积从最低16位的容与n相乘
movdx,[str1]
muldx
clc
addax,[p+10];前一次的进位与当前乘积的低16位容相加
jnck1;判断是否产生进位
movWORDptr[p+10],1
addax,[p];前一个积的高16位与现在积的低16位相加
jmpk2
k1:
addax,[p]
jnck3;判断是否产生进位
movWORDptr[p+10],1
jmpk2
k3:
movWORDptr[p+10],0
k2:
mov[si],ax
mov[p],dx
addsi,2
decbx
cmpbx,0
jnzlop3
movbx,[p+2]
clc
adddx,[p+10]
cmpdx,0
jzre;判断(n-1)!
乘积的最高16位容与n的乘积的高16位是否为0
incbx
mov[si],dx
re:
movax,[str1]
cmpax,9000h;判断是N!
乘积的容高位部分是否要存到es中
jncre1
jmpre2
re1:
cmpcx,1
jas4
re2:
incWORDptr[str1];乘数增1
leasi,str2
movWORDptr[p],0
movWORDptr[p+10],0
looplop2
decbx
movcx,bx
lop4:
addsi,2
looplop4
incbx
addbx,bx
incsi
jmplop5
s4:
incWORDptr[str1];若N的值超过8000h,8000h*8001h*8002h*N
mov[p+6],bx
mov[p+8],bx
leasi,str2
leadi,str3
moves:
[di],dx
movWORDptr[p],0
movWORDptr[p+10],0
movbx,1
deccx
lop6:
mov[p+4],bx
lop7:
movax,[si]
movdx,[str1]
muldx
clc
addax,[p+10]
jnck4
movWORDptr[p+10],1
addax,[p]
jmpk5
k4:
addax,[p];前一个积的高16位与现在积的低16位相加,产生进位
jnck6
movWORDptr[p+10],1
jmpk5
k6:
movWORDptr[p+10],0
k5:
mov[si],ax
addsi,2
mov[p],dx
decWORDptr[p+6]
movax,[p+6]
cmpax,0
jnzlop7
movax,[p+8]
mov[p+6],ax
lop8:
movax,es:
[di]
movdx,[str1]
muldx
clc
addax,[p+10]
jnck7
movWORDptr[p+10],1
addax,[p]
jmpk8
k7:
addax,[p];前一个积的高16位与现在积的低16位相加,产生进位
jnck9
movWORDptr[p+10],1
jmpk8
k9:
movWORDptr[p+10],0
k8:
moves:
[di],ax
adddi,2
mov[p],dx
decbx
cmpbx,0
jnzlop8
movbx,[p+4]
clc
adddx,[p+10]
cmpdx,0
jzre4
incbx
moves:
[di],dx
re4:
incWORDptr[str1]
leasi,str2
leadi,str3
movWORDptr[p],0
movWORDptr[p+10],0
deccx
cmpcx,0
jnzlop6
decbx
movcx,bx
lop9:
adddi,2
looplop9
incbx
addbx,bx
incdi
lop10:
decbx;若N>8000h,输出N!
乘积的高位容
moval,BYTEptres:
[di]
movch,al
movcl,4
shral,cl
cmpal,09h
jaop3
addal,30h
jmpip3
op3:
addal,37h
ip3:
movah,2
movdl,al
int21h
moval,ch
andal,0fh
cmpal,09h
jaop4
addal,30h
jmpip4
op4:
addal,37h
ip4:
movah,2
movdl,al
int21h
decdi
cmpbx,0
jnzlop10
movbx,[p+6]
decbx
movcx,bx
lop11:
addsi,2
looplop11
incbx
addbx,bx
incsi
lop5:
decbx;输出N!
的乘积
moval,BYTEptr[si]
movch,al
movcl,4
shral,cl
cmpal,09h
jaop1
addal,30h
jmpip1
op1:
addal,37h
ip1:
movah,2
movdl,al
int21h
moval,ch
andal,0fh
cmpal,09h
jaop2
addal,30h
jmpip2
op2:
addal,37h
ip2:
movah,2
movdl,al
int21h
decsi
cmpbx,0
jnzlop5
next:
movah,1
int21h
movah,4ch
int21h
codeends
endstart
六、程序运行结果与分析
若输入的16进制数N为000A(10进制为10),程序运行后输出的N!
应为375F00(H)。
程序运行结果如图2所示。
图2N=000A
若输入的16进制数N为0064(10进制为100),虽然答案不能手算出来,但根据理论N!
的低位应该为0。
程序运行结果如图3所示。
图3N=0064
根据这两个结果,我认为该程序应该是正确的。
七、实验总结
本次实验是编写N!
的程序。
在这次实验中我遇到了许多困难,一些是自己考虑不周引起的,一些是自己知识掌握不牢靠引起的,还有一些是由于自己粗心引起的。
所有的这些坎坷,都催化着我那稚嫩的程序慢慢地完善和严谨。
一开始我没考虑到阶乘乘积的前一个字中的容与乘数相乘后的积的高16位与阶乘乘积的后一个字的容与乘数相乘所得的积的高16位相加后,它们的和产生进位的问题。
在做到数据段已存不下阶乘的积,要把多出的数据放到附加段时。
由于知识掌握的不牢靠,不知道附加段的数据传输要在[di]前加es。
导致程序输出一直出错。
在快完成程序时,由于自己的马虎。
定义好附加段的容后,忘加了dup(?
)。
导致算N很大时的阶乘一直出错。
虽然这次实验编写的难度很大,但我感到我的汇编能力比起以前有了很大的提高,同时也巩固我所学的知识。
最后,程序虽然能实现0到FFFFH的阶乘了,但我感到这程序还不友好。
因为你输入的数据必须是4位16进制数,如果高位没有,必须加0,补足4位。
这就多了一步,即要把所要求的10进制数先转成16进制数才能运行程序。
所以我认为程序可以把输入部分优化,使输入10进制数,在程序中转成对应的16进制数。