课程设计任务书
学生姓名 王 丽 专业班级 软件0302班
指导老师 陈天祥 工作单位 武汉理工大学
题 目:打印完全数
一个数,若约数(不含它本身)的和恰好等于它本身就称为完全数
初始条件:
理论:学完汇编课程,掌握汇编语言的使用。
实践:计算机实验室提供计算机及软件环境。如果自己有计算机可以在其上进行设计。
要求完成的主要任务:
1. 本次课程设计着重于理论设计,同时培养动手能力。要求运用自己所学知识进行设计实现,体现自己的知识掌握水平。所作设计需进行论证,一方面是从理论上进行推理验证,另一方面是实验论证。
2. 阅读有关的参考资料,熟悉开发工具,运用软件工程设计方法,进行系统总体分析与设计, 规划出系统的总体机构,每个功能的分布情况,以形成系统的框架设计。
3. 程序用汇编语言开发完成, 严禁抄袭(发现后抄袭者和被抄袭者一律不及格)。
4.完成整个程序的设计及调试、测试工作后,应提供相应的课程设计报告书及程序总体分析与算法设计和源程序代码等。
5.课程设计报告书内容:(1) 设计题目 (2) 设计要求 (3) 设计思路及程序清单 (5) 运行结果 (6) 心得体会
6.要求按格式规范撰写课程设计报告文档, 文档中包括系统结构图,代码设计说明以及各功能模块程序的设计说明和各功能选项的使用要求及条件,各输入输出数据的约束条件及代码的使用等。
7.课程设计报告格式应尽可能规范,易读易懂,说明问题;学生自己排版、打印全部课程设计报告书内容;学生要按指定时间上交课程设计报告书。
时间安排:
1、12月26日至12月27日 接受课程设计, 阅读有关的参考资料,熟悉开发工具,运用软件工程设计方法,对设计题目进行总体分析与算法设计。.
2、12月28日至12月29日 编写程序, 到实验室进行程序调试。
3、12月30日至12月31日 继续到实验室进行程序调试、完善。撰写课程设计报告书,到实验室进行编缉排版, 交课程设计报告书。
指导教师签名: 年 月 日
系主任(或责任教师)签名: 年 月 日
1. 设计题目
打印完全数
2. 设计要求
用汇编程序MASM,编写一个程序,打印10000以内的完全数。若一个数的约数(不含它本身)的和恰好等于它本身,则该数是完全数。用循环除法(除数从2到被检测数)循环判断2――10000的数是否是完全数。
根据题目,运用所学的汇编知识和程序设计知识,完善设计思路,尽量使程序完整,具有模块化,易懂;熟悉汇编程序环境,掌握汇编命令和汇编语言,增强动手能力;增强独立解决问题的能力。
3. 设计思路
3.1原始条件及参数:
被除数以双字为单位,高16位保存在DX中,低16位保存在AX中,初始值为2;
检测范围用n 来限定
除数以字位单位,用count表示,保存在BX中,初始值为2
约数和保存在CX中,初始值为1
3.2算法设计及流程图:
3.2.1 主程序算法及流程图:
初始条件:设i为被除数,j为除数,t为余数,c为约数和
Int i=2 ; //被除数从2开始
循环体:While (i<=10000) //求10000以内的完全数
{ int j=2 , c=1; //除数从2开始,约数和初始为1
While ( j<=i ) //除数小于被除数
{ t = i mod j ; //求模
If ( t==0)
{ c=j+c;} //如果能够整除,保存约数和
j++ ;} //除数自增
if (c==i)
print i ; //打印完数
i++ ; } //被除数自增
退出:Exit
3.2.2 print子程序算法及流程图
初始条件:被除数保存在AX中,将除数设置为10
将BX,CX压入堆栈,保护现场
循 环 体:被除数除以10,
将余数压入堆栈,堆栈中数目加1
继续除以10,直到被除数不可以再除
弹出堆栈中的内容
退 出:Exit
4. 程序清单
data segment
n dw 10000 ;求10000以内的完数
count dw ? ;作为除数
data ends
code segment
assume cs:code,ds:data
start: mov ax,data
mov ds,ax
mov n,2 ;从2开始判断是否视完数
l1: mov count,2 ;cx保留约数和,初始值为1
mov cx,1 ;bx作为除数,从2开始
l2: mov ax,n
push ax ;保存现场,保留ax的值
mov dx,0 ;被除数的高16位置0
div bx
cmp dx,0
jnz l3 ;dx保存余数,若余数不为0,则转向l3,继续除下一个除数
add cx,bx ;若余数为0,则把除数相加
l3: inc count ;除数加1
pop ax ;ax出栈
cmp ax,count
jnz l2 ;比较被除数和除数,若相等,则转向l2,
cmp n,cx
jnz l4 ;比较约数和与被除数是否相等,若相等,转向l4,测试下一个数
mov dx,0
mov ax,n
call print ;调用子程序,打印完数,每显示一个完数,紧跟一个空格
mov dl,' '
mov ah,02h
int 21h
l4: inc n ;测试2――10000的完数
cmp n,10000
jnz l1
mov ah,4ch
int 21h
print proc ;打印子程序
push cx ;保护现场
push bx
mov cx,0ah ;cx作除数,以10为基数
mov bx,0 ;bx作计数器,计算压入堆栈的完数个数
print_l1:
mov dx,0
div cx
push dx ;将余数压入堆栈保留
inc bx ;压入数目增加1
cmp ax,0
jnz print_l1 ;反复调用print_11,直到被除数不能再除
print_l2:
pop dx ;循环弹出余数
add dl,30h ;余数以ASCII码的表示
mov ah,02h
int 21h ;输出调用
dec bx ;堆栈中数的个数减1
jnz print_l2 ;弹出堆栈中所有的数
pop bx ;还原现场
pop cx
ret
print endp ;子程序结束
code ends
end start ;程序结束
5. 运行结果
该程序是:查找10000以内的完全数,文件名为wanshu.asm,执行结果如下:
6. 心得体会
6.1程序设计体会
在程序设计的过程中,我体会到了一些程序设计的基本方法和设计技巧,这些有助于拓宽我的解题思路,一定程度上帮助我解决设计上存在的问题。
6.1.1算法设计
在此过程中,除数,被除数,约数和的初始值的定义至关重要。由于本程序要反复除以除数,并把余数与0比较,把约数进行相加,因此应该尽量控制程序作除法运算的次数,达到最快的运行速度。在此程序中,我把除数的初始值设置为2,约数和的初始值设置为1,避免了被除数屡次除以1以及约数屡次从1开始相加。每测试一个数字,除数都从2开始,循环除,直至达到被除数本身(根据题目要求,除数达到”被除数/2”即可满足循环条件)。这影响了程序的运行速度,是这个程序的一个缺陷。
6.1.2程序编写的规范性
编写程序要注意格式的规范性。在此过程中,我的程序出现了前后不对应的情况,系统提示程序没有结束,经过检查才发现,最后缺少一个结束语句。汇编的每一段都应该有开始和结束的标志;同时,使用汇编的语句时要注意简洁和清晰,当一种操作可以用不同的语句表示时(如loop 相当于dec 和jnz两个语句的组合),要比较不同代码的优缺点,被选择使用的语句应该能表现程序的结构性。
6.1.3合理使用寄存器
由于要求打印10000以内的完数,理论上除数至少应该到达5000,用8位二进制表示此数是远远不够的。但如果除数用16位表示,被除数将占用32位。受到机器及运行环境的限制,无法使用386以上机型中的EBX,EAX,ECX,EDX等寄存器,因此,我采用DX,AX分别保存被除数的高16位和低16位,对于除法运算的结果,使用系统默认处理。商保存在AX中,余数保存在DX中;同时,利用累加器CX的特殊功能,用其保存约数和,以方便计算。
6.1.4合理使用堆栈
在编写程序的过程中,我明显的感觉到寄存器不够用。因此,我利用堆栈保护现场,保存相关的数据。虽然入栈,出栈的操作频繁,可能会一定程度上延缓了程序的执行速度,但它解决了寄存器数量上的限制。另外,由于除法计算的余数和商分别保存到DX和AX中,而AX在后续的程序中要使用到,因此要着重注意对AX的数据保存。
6.1.5变量的使用
AX既要用来存放被除数,也需要存放除法所得的商,因此,我设置了变量n,通过”mov ax, n ” 语句可以把待检测的数在需要时临时送入AX,冲掉AX内原来的值。另外,我还设置了变量count,用寄存器BX保存除数,利用count的自增来实现除数的改变,通过 ” mov bx, count “语句把除数送入BX。变量与堆栈联合使用,可以方便的改变和保存所需要的数据,使程序简单易懂。
6.2程序错误及改正
在程序编译的过程中,遇到了一些令我措手不及的错误.由于初次遇到此类问题,我花费了大量的时间阅读代码,浏览程序,并查找课本和资料,找出指令的差别尤其是中断指令部分的差别.
6.2.1 结束命令错误
最初的编译,遇到该问题,仔细检查源代码,才发现l4段的退出部分出现问题.我将显示命令 ” mov ah, 09h int 21h ” 误当作结束命令.改为 ” mov ah, 4ch int 21h “ 后,顺利结束了该程序,也解决了运行时出现的该问题。
6.2.2 除数溢出错误
除数溢出问题是本次课程设计中我遇到的最困难的问题.
开始时我把除数定义在2——“被除数/2”
方案一:“被除数/2”用右移一位AX实现
当AX中为1时,右移一位则AX为0,除数为0 , 出现逻辑错误;当AX为奇数时,右移一位则结果不精确,运行结果同样出现错误.
方案二:“被除数/2”用除2的除法实现
由于程序由两层循环嵌套组成,又调用了一个输出完全数的子程序,寄存器在各段中使用频繁,数据的保存和恢复频繁,容易破坏程序的条理性.而增加一次除法大大增加了寄存器的负荷,因此该方案也不是一种好的方案.
于是,我把除数定义在2——被除数的范围内,解决了除数溢出的问题和寄存器的限制,但同时也给程序的计算增加了“被除数/2”的复杂度。
6.3课程设计的不足
我设计和编写的程序完成了题目的要求,可以查找出任意正数范围内的完全数,但它存在两个不足:
第一: 现在的程序,如果要修改完全数的查找范围,就必须在源程序中改动,重新定义n的值.但如果在程序之初给出提示,让用户输入所要查找的范围,并把该数赋值给n,从而通过n重新定义被除数就更完善了.
第二: 考虑到寄存器数量上的限制和程序的可读性和条理性的要求,我扩大了除数的范围,使除数不再溢出.但这在一定程度上延迟了程序的执行速度.如果能找出协调这二者的方法,程序就更完善了.
6.4课程设计的收获
在本次的课程设计过程中,我最大的收获就是学到了不少新的知识,同时可以把自己学到的汇编语言的知识和以前学的程序设计的知识应用到实践中, 熟悉了开发环境 ,提高了自己的动手能力, 并顺利地完成了此次的任务.课程设计让我从中得到莫大的信心,鼓励,快乐和成就感.
编程过程中,我遇到了一些困难.这时,我通过上网查询和去图书馆查找资料解决问题,有效地利用网络资源和学校图书资源,同时也了解了更多的知识获取的途径,扩大了自己的知识面.
遇到问题时,多数情况下我是自己独立解决的,这锻炼我独立思考问题和独立解决问题的能力;如果自己通过查找资料无法解决,我就向老师和同学寻求帮助,不但学到了新的,更完善解决问题的方法,还学会了与人沟通,与人交流.我认识到有时候,其他人的一点提示,就会令自己茅塞顿开,得到灵感.因此,在作课程设计时,不要吝惜自己的思路和想法,尽可能多的与大家的交流.许多时候,我们都能从中得到进步,得到提示,甚至得到更好的方案.
同时,我也发现了自己的一些问题.例如,编写程序不够规范,总是在出现问题时,才意识到格式和编程习惯的重要性,然后手忙脚乱的去修改,给自己的自信和成就感带来很大的挑战.另外,为了图方便,我把在实验室和寝室修改过的程序直接运行,结果却不能导入MASM环境,不能出现编译,连接和运行的结果,经过同学的提示,我才知道在进行程序的编译前,要将程序在EDIT下打开.由此,我意识到,许多工作都像这样,要一步一步的来,不能耍小聪明,图省事.
本次课程设计,对我帮助很大.它提高了我的理论知识和和实践动手能力;提高了我独立思考问题和解决问题的能力;同时,增强了我与人探讨问题,交流思路的意识;此外,它还让我发现了自己在编程习惯上的许多不足,对以后的编写程序和设计解题思路有很大的启发.
在以后的学习和实践中,我会不断督促自己,不断提高,不断进步.
第二篇:汇编语言 课程设计
;《汇编语言》,第二版,王爽,清华大学出版社;p211;可直接运行,txt文件中无需修改任何内容包括汉字说明,若出错可能与操作系统有关,可进入debug执行看看,再退出debug;重新运行一次.exe文件:举例若最终生成文件名1.exe,当直接虚dos下运行不成功时,在dos下先debug 1.exe后,q命令退出,;再在dos下运行1.exe看是否可行(输命令时注意文件路径,我的win7虚dos下是可行的,主要是操作系统的问题我认为)assume cs:codedata segmentdb '1975','1976','1977','1978','1979','1980','1981','1982','1983','1984','1985'db '1986','1987','1988','1989','1990','1991','1992','1993','1994','1995'dd 16,22,382,1356,2390,8000,16000,24486,50065,97479,140417,197514dd 345980,590827,803530,1183000,1843000,2759000,3753000,4649000,5937000dw 3,7,9,13,28,38,130,220,476,778,1001,1442,2258,2793,4037,5635,8226dw 11542,14430,15257,17800data endstable segmentdb 21 dup('year sumn ne ?? ')table endsstring segmentdb 16 dup(0)string endsstack segmentdw 32 dup(0)stack endscode segmentstart: mov ax,datamov ds,axmov bx,0mov ax,table mov ss,axmov bp,0mov si,0mov cx,21zhu: mov ax,[bx]mov [bp],axmov ax,[bx+2]mov [bp+2],ax;将年代传到table段对应位置mov ax,[bx+84]mov [bp+5],axmov ax,[bx+86]mov [bp+7],ax;将收入传到table段对应位置mov di,bxsub di,simov ax,[di+168];用di=bx-si+168来确定雇员数对应data段中偏移地址mov [bp+0ah],ax;将雇员数传到table段对应位置mov ax,[bp+5]mov dx,[bp+7]div word ptr [bp+0ah]mov [bp+0dh],ax;算出人均收入(取整)放到table段对应位置add si,2 add bx,4add bp,10hloop zhu;上面部分可以说是《汇编语言》p172,实验7中将Power idea公司从19xx年成立一直到19xx年基本情况数据存到table段中;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@mov ax,tablemov es,axmov bp,0mov ax,stackmov ss,axmov sp,64;告诉cpu重新设置新的数据段和栈段,因为data段后续无需跟踪了,ds后续dtoc子函数用到且中间还用table段;所以table段最好用esmov ax,stringmov ds,axmov si,0mov dh,2;设置字符串显示行mov cx,21zhu0: push cxmov dl,5;设置字符串显示列mov cl,2;显示字符串颜色设置mov ax,es:[bp]mov [si],axmov ax,es:[bp+2]mov [si+2],axmov byte ptr [si+4],0call show_str;显示年份,由于年份table段中存储的就是字符串,所以无需调用dtocadd dl,20push dxmov ax,es:[bp+5]mov dx,es:[bp+7]call dtocpop dxcall show_str;显示年总收入add dl,20push dxmov ax,es:[bp+10]mov dx,0call dtocpop dxcall show_str;显示雇员数add dl,20push dxmov ax,es:[bp+13]mov dx,0call dt
ocpop dxcall show_str;显示人均收入 inc dhadd bp,16pop cxloop zhu0mov ax,4c00hint 21h;*********************************************************************************************;子程序dtoc描述:;功能:将dword型数据转变为表示十进制的字符串,字符串以ASCII码0为结尾符;参数:(ax)=dword型数据的低16位,(dx)=dword型数据的高16位; ds:si指向字符串的首地址;返回:无dtoc: push axpush bxpush cxpush dxpush sipush dimov di,0s: mov cx,10call divdw ;除以10取商和余数add cl,30hpush cx;将余数对应ASCII码入栈inc di;标记有多少个数进入栈mov cx,dxjcxz d16jmp short sd16: mov cx,axjcxz s0;判断商是否为0jmp short ss0: pop dxmov [si],dl;将十进制数从高到低位对应ASCII码送入指定内存inc sidec dimov cx,dijcxz okjmp short s0ok: mov byte ptr [si],0pop dipop sipop dxpop cxpop bxpop axret;子程序描述:;功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果为dword型。;参数:(ax)=dword型数据的低16位; (dx)=dword型数据的高16位; (cx)=除数;返回:(dx)=结果的高16位,(ax)=结果的低16位; (cx)=余数divdw: ;不能将所有寄存器中内容入栈出栈,因为结果放在寄存器中返回mov bx,ax ;保护ax值mov ax,dxmov dx,0div cx ;将高16位数视为一个简单的16位被除数参与运算push ax ;结果的高16位入栈mov ax,bxdiv cx ;ax记录结果的低16位,dx记录余数mov cx,dxpop dxret;**********************************************************************************************;子程序show_str:;功能:在屏幕上指定的位置,用指定的颜色,显示一个用0结束的字符串,标志结束位0不显示。;参数:(dh)=屏幕上行号(取值范围0-24),(dl)=屏幕上列号(取值范围0-79),; (cl)=颜色,ds:si指向要显示内存中字符串的首地址show_str: push axpush bxpush cxpush espush simov ax,0b800h;es记录显存的段地址mov es,axmov al,160;bx记录首个字符写入显存的偏移地址mul dhmov bx,axmov al,2mul dladd bx,axsh: mov al,clmov cl,[si]mov ch,0jcxz ok1mov es:[bx],cl;字符ASCII码值写入显存mov es:[bx+1],al;字符颜色写入显存mov cl,aladd bx,2inc sijmp short shok1: pop sipop espop cxpop bxpop axretcode endsend start