汇编_子程序设计_阶乘
- 格式:doc
- 大小:52.00 KB
- 文档页数:4
本程序作者cabbage功能:计算1亿以内数的阶乘E-mail:1225673051@;**********************求阶乘程序,十进制输入一个数,十进制输出其结果*********************STROUT MACRO ;宏,DOS功能调用,设置字符串输出入口参数MOV AH,09HINT 21HENDMCHAR_IN MACRO ;宏,DOS功能调用,设置字符输入入口参数MOV AH,01HINT 21HENDMDATAS SEGMENT PUBLICDATA1 DB 10H DUP(0)LEN1 DW ?LEN2 DW ?CONST1 DW 30CONST2 DW 40INDEX DB 10H DUP(0)STR0 DB '********************FACTORIAL**********************$'STR1 DB 0AH,0DH,'Please input the num:$'STR2 DB 0AH,0DH,'Error!$'STR3 DB 0AH,0DH,'The result is:$'STR4 DB 0AH,0DH,'****************************************************$'STR5 DB 0AH,0DH,'Thank you for using!$'DATA3 DB 0FF24H DUP(0)DATAS ENDSDATAS1 SEGMENT PUBLICDB 0FFFFH DUP(0)DATAS1 ENDSDATAS2 SEGMENT PUBLICDATA2 DB 0FFFFH DUP(0)DATAS2 ENDSDATAS3 SEGMENT PUBLICDB 0FFFFH DUP(0)DATAS3 ENDSSTACKS SEGMENT STACKDW 2000H DUP(?)TOP LABEL WORDSTACKS ENDSCODES1 SEGMENTASSUME CS:CODES1,DS:DATAS,SS:STACKS,ES:DATAS2START:MOV AX,DATASMOV DS,AXMOV AX,STACKSMOV SS,AXMOV AX,DATAS2MOV ES,AXMOV SP,OFFSET TOPMOV LEN1,OFFSET DATA2MOV LEN2,OFFSET DATA3MOV DX,OFFSET STR0STROUTs1:CALL ZERO ;清零DATA1,DATA2,DATA3,INDEX,为保证运行结果不受前次影响XOR AX,AXXOR BX,BXXOR CX,CXXOR DX,DX ;清零AX,BX,CX,DX等寄存器,为保证运行结果不受前次影响MOV DX,OFFSET STR1STROUTXOR SI,SIdo1:CHAR_INCMP AL,0DHJZ d1CMP AL,'0'JB errorCMP AL,'9'JA errorSUB AL,'0'MOV DS:BYTE PTR [SI],AL ;输入原始数据,按位输入,高位先输INC SIJMP do1d1:CMP SI,0JZ exitMOV CX,SIXOR DI,DIdo2:MOV AL,DS:BYTE PTR [SI-1]MOV ES:BYTE PTR DATA2[DI],AL ;先给DATA2中赋值,使其等于输入的数据INC DIDEC SILOOP do2MOV CX,DIXOR SI,SIXOR DI,DIdo3:MOV AL,ES:BYTE PTR DATA2[DI]MOV DS:BYTE PTR [SI],ALINC DI ;再将DATA1中的数据实现,高位存放在地址较大的存储单元INC SILOOP do3s2:XOR AX,AXCALL FAR PTR FAC ;调用阶乘计算函数CMP SI,1 ;当还没有计算到1时,再次进入阶乘函数JNZ s2MOV AL,DS:BYTE PTR [SI-1]CMP AL,1JZ s3JMP s2s3:CALL FAR PTR RESULT ;输出结果JMP s1error:MOV DX,OFFSET STR2STROUTJMP s1exit:MOV DX,OFFSET STR5STROUTMOV AH,4CHINT 21HCODES1 ENDS;*********************************************************CODES2 SEGMENTASSUME CS:CODES2,DS:DATAS,SS:STACKS,ES:DATAS2;递归子过程,计算阶乘,没当递归次数大于等于5000时,返回再次进入,降低栈对递归的限制FAC PROC FARINC AXPUSH AXdo6:MOV AL,ES:BYTE PTR DATA2[DI-1]DEC DICMP AL,0JZ do6INC DICMP DI,CONST2JB s4CALL FAR PTR DZEROs4:CMP SI,1JNZ s5MOV AL,DS:BYTE PTR [SI-1]CMP AL,1JZ s9JMP s6s5:MOV CX,SIDEC CXXOR BP,BPMOV AL,DS:BYTE PTR [BP]SUB AL,1PUSHFAASMOV DS:BYTE PTR [BP],ALdo4:INC BPMOV AL,DS:BYTE PTR [BP]POPFSBB AL,0PUSHFAASMOV DS:BYTE PTR [BP],ALLOOP do4POPFMOV AL,DS:BYTE PTR [SI-1]CMP AL,0JNZ s7DEC SIJMP s7s6:MOV AL,DS:BYTE PTR [SI-1]SUB AL,1MOV DS:BYTE PTR [SI-1],ALs7:CALL FAR PTR MULTPOP AXCMP AX,1388HJZ s8CALL FAR PTR FACs8:RETs9:POP AXRETFAC ENDPCODES2 ENDS;*********************************************************;乘法运算函数,用于多位非压缩码BCD数(DATA1)与多位非压缩码BCD数(DATA2)的乘法运算;,并将结果存放在DATA2中。
ARM汇编语言程程序设计精讲
阶乘操作实例解析
求一个数的阶乘(64位结果)
用ARM汇编语言设计程序实现求20!(即20的阶乘),并将其64位结果放在[R9:R8]中。
(R9中存放高32位)
解:程序设计思路:64位结果的乘法指令通过两个32位的寄存器相乘,可以得到64位的结果,在每次循环相乘中,我们可以将存放64位结果两个32位寄存器分别与递增量相乘,最后将得到的高32 位结果相加。
程序设计流程如图7-1所示:
程序设计流程图
程序代码如下:
在ARM集成开发环境下编程ADS:
;
声明代码段Fctrl
AREA
Fctrl,CODE,READONL Y
ENTRY ; 标识程序入口
CODE32 ; 声明32 位ARM 指令START
MOV R8 , #20 ;低位初始化
MOV R9 , #0 ;高位初始化
SUB R0,R8,#1 ;初始化计数器
Loop
MOV R1 , R9 ;暂存高位值
UMULL R8 , R9 , R0 , R8 ;[R9:R8]=R0*R8
MLA R9 , R1 , R0 , R9 ;R9=R1*R0+R9
#1 ;计数器递减
,
R0
,
SUBS R0
BNE Loop ;计数器不为0继续循环Stop
B Stop
END ; 文件结束
程序执行后输出结果如下:R8=0x82B40000
R9=0x21C3677C。
微机原理实验报告-------颜色的排列组合方式院系:自动化班级:学号:姓名:日期:成绩:1.题目在实际中,有红黄蓝绿等7种颜色,按照排列组合方式,分别计算出有多少种排列方式?如果减少一种颜色,又有多少中排列呢?2.题目分析题目中给去n种(n=7)颜色,要求我们计算可能出现的组合种数,这是数学中常见的排列组合问题。
题目的意思是指的传统的排列组合,不许有重复颜色的,否则与生活习惯就不符合了。
这个咱们就熟悉了,对于n种颜色,应该有nA种排列方式。
我们知道,nnA在数值上就是n的阶乘,现在程序的对象成为求阶乘了。
n对于阶乘,我的思路是利用循环,设计一个累加变量兼被乘数x,用n来作为结束判断,当x>n时,累乘循环结束,现在就得到了相应的种类数。
但是内存中的数值是以16进制存放的,还需要一步进制转换才能进行显示。
我的算法是:开辟5个空间的变量result1存放个位数字,给bx赋值10,(※)把dx清零,用{dx,ax}除以bx,得到的余数放在dx中,就是个位数的十进制表示,在转放到result1的第一个地址中。
此时商数存在ax中,再重复(※)之后的内容,直到全部转化完。
显示的算法是十进制数字加上30h,变为ASCII码,利用INT 21H中断循环显示各位数字。
程序还给阅读者提供了选择权,允许读者进行输入,当读者输入一个数据n(n<=7)时,程序会根据输入,显示出相应的运算结果,这样当给定的样色种类变化时,就不用对程序本身进行更改了,可谓更加方便灵活。
3.程序框图4.程序编写CRLF MACRO ;定义回车换行的宏MOV DL,0DHMOV AH,2INT 21HMOV DL,0AHMOV AH,2INT 21HENDMSTACK SEGMENT STACK ;初始定义DW 100 DUP(?)STACK ENDSDATA SEGMENTSTRING DB 'ENTER SORT OF COLOUR: ','$' ;输入提示字符串RESULT1 DB 5 DUP(0) ;用来存储结果的各位数字DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,SS:STACKSTART:MOV AX,DATAMOV DS,AXMOV AX,STACKMOV SS,AXMOV DX,OFFSET STRINGMOV AH,9INT 21HMOV AH,1 ;输入样色的种类INT 21HSUB AH,AHSUB AL,30HMOV CX,AX ;颜色的种类用来控制循环CRLFMOV AX,1MOV BX,1LP:MUL BXINC BXLOOP LPLEA DI,RESULT1 ;LP循环求阶乘MOV BX,10MOV CX,4LOOP1:DIV BXMOV [DI],DL ;LOOP1将16进制转为10进制INC DISUB DX,DXLOOP LOOP1DEC DIMOV CX,4DISPLAY: ;DISPLAY用来显示10进制的各位数字ADD BYTE PTR[DI],30HMOV DL,[DI]MOV AH,2INT 21HDEC DILOOP DISPLAYMOV AX,4C00HINT 21HCODE ENDSEND START5.运行结果6. 结果讨论排列中数是颜色种类n的阶乘,比较5种6种和7种的数值可发现,120,720和5450相差很大。
递归计算设计实验报告1.设计思想(附流程图)尽量实现模块化流程。
2.代码DATAS SEGMENTdata1 db 'INPUT N:','$';此处输入数据段代码data2 db 4 dup('0')n dw 0fac dw 00,00data4 db 11 dup('$')DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码STACKS ENDSCODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKS START:MOV AX,DATASMOV DS,AXlea dx,data1mov ah,09hint 21hlea dx,data2mov ah,0ahint 21hcall aa;转十进制mov ax,cxcall bb;求阶乘call cc;转十进制,输出MOV AH,4CHINT 21Haa procmov ax,0push axlea bx,data2mov ch,0mov cl,[bx+1]mov si,1p1: mov dx,0pop axmov bx,0ahmul bxmov dx,axlea bx,data2mov al,byte ptr [bx+1+si]sub al,30hadd ax,dxpush axinc siloop p1pop cxmov n,cxretaa endp;此处输入代码段代码bb proccmp ax,0jne end1mov ax,01hmov dx,0jmp end2end1:push axdec axcall bbpop bxmov word ptr fac[2],dxmul bxpush axpush dxmov ax,word ptr fac[2]mul bxpop dxadd dx,axpop axend2:retbb endpcc procmov word ptr fac,axmov word ptr fac[2],dxmov bx,0ahmov cx,0mov dx,0p3: mov ax,word ptr fac[2] div bxmov word ptr fac[2],axmov ax,word ptr facdiv bxpush dxmov dx,0inc cxmov word ptr fac,axcmp ax,0jnz p3mov dl,0ahmov ah,02hint 21hmov dl,byte ptr data2[2]mov ah,02hint 21hmov al,byte ptr data2[1]cmp al,2jnz gomov dl,byte ptr data2[3]mov ah,02hint 21hgo: mov dl,21hmov ah,02hint 21hmov dl,3dhmov ah,02hint 21hp4: pop dxmov dh,0add dl,30hmov ah,2hint 21hloop p4retcc endpCODES ENDSEND START3.测试过程与结果4.有关设计编写调试体会本次实验的目的是通过对子程序的应用来实现阶乘的计算,其特点是利用子程序将主程序分为几个小部分,逐步解决问题;其中应用的难点在于对子程序的递归调用,调用自身来进行反复计算时要注意子程序开始执行以及递归调用时的条件,理清逻辑结构才能避免出现混乱。
汇编语言程序掌握子程序的设计1. 引言1.1. 目的1.2. 范围1.3. 定义1.4. 参考资料2. 前置知识2.1. 汇编语言基础2.1.1. 寄存器2.1.2. 指令集2.1.3. 内存管理2.2. 子程序概览2.2.1. 子程序的定义2.2.2. 子程序的调用2.2.3. 堆栈的使用3. 子程序设计原则3.1. 单一职责原则3.2. 代码重用性3.3. 可读性和可维护性 3.4. 参数传递规范3.5. 返回值处理规范4. 子程序设计的步骤4.1. 确定子程序功能 4.2. 绘制流程图4.3. 划分子任务4.4. 设计输入和输出4.5. 编写子程序代码4.6. 测试和调试5. 示例子程序:字符串逆序 5.1. 子程序说明5.2. 输入和输出5.3. 伪代码5.4. 代码实现5.5. 测试结果6. 示例子程序:计算阶乘 6.1. 子程序说明6.2. 输入和输出6.3. 伪代码6.4. 代码实现6.5. 测试结果7. 示例子程序:查找最大值7.1. 子程序说明7.2. 输入和输出7.3. 伪代码7.4. 代码实现7.5. 测试结果8. 附录8.1. 附件A:汇编语言参考手册8.2. 附件B:示例代码[注:法律名词及注释]1. 版权:指对原创作品的独占使用权,由作者享有并可通过法律手段维护的权利。
2. 商标:指用于区分商品或服务来源的标识,享有独占使用权并受法律保护。
3. 专利:指对发明的技术解决方案的专有权,持有人可以在特定领域内禁止他人复制、制造、销售该技术。
4. 许可:指授予他人特定权利的行为,持有人可以限定他人在特定条件下使用或复制作品。
[附件]1. 附件A:汇编语言参考手册2. 附件B:示例代码。
DA TAS SEGMENTstring db "Please input a number(0-10000):" ,0dh,0ahwrongstring db " A number please! ",0ah,0dh,'$'inputbuffer db 6,?,6 dup(?)c10 dw 10 ;输入时进制转换的数n dw ? ;要求阶乘的数m dw ? ;步长c dw ? ;进位i dw ? ;outputbuffer dw 30000 dup(?) ;DA TAS ENDS;****************************************************************************** *STACKS SEGMENT;此处输入堆栈段代码STACKS ENDS;****************************************************************************** *CODES SEGMENTASSUME CS:CODES,DS:DATAS,SS:STACKSSTART:MOV AX,DATAS ;MOV DS,AX ;;-------------------------------------------------------main proccall input ;call fractor ;mov cx,diroutput: ;循环输出push cx ;mov di,cx ;call output;pop cxdec cxcmp cx,0jge routputdisplaylength:mov dl,0dhmov ah,2mov dl,0ahmov ah,2int 21hexit:;mov ah,07h ;int 21h ;mov ax,4c00h ;INT 21H ;;main endp ;;-------------------------------------------------------;--------------------------------------------------------input proc nearlea bx,stringmov cx, 33disstring:mov dl,[bx]mov ah,2int 21hinc bxloop disstringjmp inputinitwronginput:lea dx,wrongstringmov ah,9int 21hinputinit:lea dx,inputbuffer ;装载输入缓冲区首地址mov ah,0ah ;输入功能代码int 21h ;从键盘输入一个数,以回车键结束mov ax,0 ;累加器清0mov cl,inputbuffer+1 ;循环次数mov ch,0lea bx,inputbuffer+2 ;装载字符存放区首地址;mul c10 ;mov dl,[bx]cmp dl,'0'jb wronginputcmp dl,'9'ja wronginput ;and dl,0fh ;add al,dl ;adc ah,0 ;inc bx ;loop inputone ;mov n,axmov dl,0dhmov ah,2int 21hmov dl,0ahmov ah,2int 21h;ret;input endp ;;----------------------------------------------------- fractor proc near ;mov cx,n ; mov i,1d ;mov m,0d;push dxmov di,0d ;mov ax,di ;mov bx,2d ;mul bx ;mov si,axpop dx;mov outputbuffer[si],1d ;ctrli: ;mov c,0mov di,0d ;; cmp di,m ; jbe done ; jmp cmpc ; done:push dx ; mov ax,di ; mov bx,2d ; mul bx ; mov si,axpop dx; mov ax,outputbuffer[si] ;mov bx,i ; mul bx ; add ax,c; ; adc dx,0; ; mov bx,10000 ; div bx ; mov c,axpush dx ; mov ax,di ; mov bx,2d ; mul bx ; mov si,axpop dx ; mov outputbuffer[si],dx ;inc di ;jmp ctrldi ; cmpc: ; cmp c,0 ; ja three1 ; jmp next ; three1: ; inc m ; mov ax,c ; mov outputbuffer[si+2],ax ;; next:inc ijng if0 ;loop ctrliif0:mov di,m ;ret ;;;;fractor endp ;;----------------------------------------------------- output proc near ;C2:push dx ;mov ax,di ;mov bx,2d ;mul bx ;mov si,axpop dx;mov bx,outputbuffer[si] ;bid proc ;mov cx,10000 ;mov ax,bx ;mov dx,0 ;div cx ;mov bx,dx;mov cx,1000 ;call ddiv ;mov cx,100 ;call ddiv ;mov cx,10 ;call ddiv ;mov cx,1call ddiv ;ret;bid endp ;;---------------------------------ddiv proc ;mov ax,bx ;mov dx,0 ; div cx ; mov bx,dx ; mov dl,al ; add dl,30h ; mov ah,02h ; int 21h ;ret;ddiv endp ;; ret ; output endp ;;--------------------------------------------CODES ENDS ; END START ;。
目录一、实验要求.......................... . (3)二、实验内容 (3)三、实验思路 (3)四、实验过程 (5)五、实验总结 (12)一、实验要求实验目的(1)、堆栈传递参数的子程序调用方法。
(2)、序递归调用方法。
(3)、伪指令:PROC,ENDP,NEAR和FAR。
(4)、指令:CALL,RET,RET n。
(5)、T指令推出EXE文件的方法。
(6)、了解怎样在汇编语言一级上实现高级语言中的数学函数。
二、实验内容1、实验内容计算N!:编写计算N阶乘的程序,数值N由键盘输入,N的值要在0到65536之间(用一个16位的字表示),结果在显示器上显示。
2、实验步骤(1)、打开开始菜单,单击运行,在对话框中输入“cmd”,进入dos窗口。
(2)、输入cd\masm5 回车,在输入edit 回车,进入汇编窗口。
(3)、输入代码。
(4)、保存代码,后缀名为.asm。
(5)、回到dos窗口,输入masm文件名保存位置,文件名回车。
(6)、调试程序,根据提示回到汇编窗口,对代码进行修改,直至出现no error及no warrings。
三、实验思路、1、算法阶乘的定义为N!=N*(N-1)*(N-2)*……2*1,从走往右翼此计算,解雇保留在缓冲区BUF中。
缓冲区BUF按由低到高依次排列。
程序首先将BP初始为N,N 不等于0获1则将N送入BUF缓冲区最低自单元中。
然后使BP一次减1,直至变化到1为止。
每次让BP与BUF的字单元按照由低到高的次序香橙。
低位结果AX仍保存在相应的BUF自单元中,高位结果DX泽送到进位子单元CY 中,作为高字香橙时从低字来的进位,初始化CY为0。
计算结果的长度随着成绩运算而不断增长,由字单元LEN指示,LEN单元初始化为1。
当最高字单元与BP香橙时,若DX不为0,则结果长度要扩展。
2、流程图四、实验过程1、源程序CRLF MACRO ;回车,换行MOV AH,02HMOV DL,0DHINT 21HMOV AH,02HMOV DL,0AHINT 21HENDMDATA SEGMENTMESS1 DB 'INPUT THE NUMBER ACCORDING TO HEXNUM!',0DH,0AH,'$' MESS2 DB 'THE RESULT IS:$'ERROR DB 'INPUT ERROR!INPUT ONCE MORE!',0DH,0AH,'$'LEN DW 1CY DW ?BUF DW 256 DUP(0)DATA ENDSSTACK SEGMENT STACK 'STACK'DW 32 DUP(?)STACK ENDSCODE SEGMENTASSUME CS:CODE,DS:DATA,ES:DATA,SS:STACKSTART: MOV AX,DATAMOV DS,AXMOV ES,AXMOV AH,09HMOV DX,OFFSET MESS1INT 21H ;显示输入提示信息CALL GETNUM ;读取键入的N值MOV BP,DX ;N值送BPCMP BP,0JZ EEECMP BP,1JZ EEE ;N=0或N=1则转EEEMOV SI,OFFSET BUF ;缓冲区首址MOV [SI],DXXXX: DEC BP ;N值减1CMP BP,0001HJZ LLL ;若为1则转LLLXOR BX,BX ;偏移指针清0MOV WORD PTR CY,0 ;进位单元清0MOV CX,LEN ;当前结果长度送CXTTT: MOV AX,[SI+BX]MUL BP ;相乘ADD AX,CY ;加低位进位JNC JJJ ;结果无进位转JJJINC DX ;有进位将高位单元加1 JJJ: MOV [SI+BX],AX ;结果送缓冲区中MOV CY,DX ;高位单元送进位单元INC BXINC BX ;一个字长度LOOP TTT ;循环CMP DX,0000HJZ BBB ;最后一次的进位为0则转BBB INC WORD PTR LEN ;长度加1MOV [SI+BX],DX ;进位送缓冲区中BBB: JMP XXXEEE: MOV SI,OFFSET BUFMOV WORD PTR b[SI],1 ;结果为1LLL: MOV AH,09HMOV DX,OFFSET MESS2INT 21H ;显示表头MOV CX,LENMOV BX,CX ;长度DEC BXSHL BX,1 ;一个字为两个字节CCC: MOV AX,[SI+BX]CALL DISPDEC BXDEC BX ;显示结果LOOP CCCMOV AX,4C00H ;结束INT 21HDISP1 PROC NEAR ;显示字符(AL)MOV BL,ALMOV DL,BLMOV CL,04ROL DL,CLAND DL,0FHCALL DISPL ;显示高位MOV DL,BLAND DL,0FHCALL DISPL ;显示低位RETDISP1 ENDPDISPL PROC NEAR ;显示一位(DL=0XH)CMP DL,3AHJB DDDADD DL,27HDDD: MOV AH,02HINT 21HRETDISPL ENDPDISP PROC NEAR ;显示4位数(HEC) PUSH BXPUSH CXPUSH DXPUSH AXMOV AL,AHCALL DISP1POP AXCALL DISP1POP DXPOP CXPOP BXRETDISP ENDPGETNUM PROC NEAR ;字符匹配程序PUSH CXREGET:XOR DX,DXGGG: MOV AH,01HINT 21HCMP AL,0DHJZ PPPCMP AL,20HJZ PPPSUB AL,30HJB KKKCMP AL,0AHJB GETSCMP AL,11HJB KKKSUB AL,07HCMP AL,0FHJBE GETSCMP AL,2AHJB KKKCMP AL,2FHJA KKKGETS: MOV CL,04HSHL DX,CLXOR AH,AHADD DX,AXJMP GGGKKK: CRLFMOV AH,09HMOV DX,0FFSET ERROR INT 21HJMP REGETPPP: PUSH DXCRLFPOP DXPOP CXRETGETNUM ENDPCODE ENDSEND START2、测试结果输入程序把程序都输入进去后,进行调试,直至出现0个错误和0个警告!调试完程序之后,输入LINK,对程序进行编译。
数的阶乘很多教材中的阶乘程序只是简单地用了阶乘的定义,算法比较简单,考虑也不够全面,其相应的程序如下:/* 数的阶乘(经典版)*/#include"stdio.h"main(){extern jiecheng(int n);int n;printf("请输入一个数:");scanf("%d",&n);jiecheng(n);}extern jiecheng(int n){long result=1;int i;for(i=1;i<=n;i++)result*=i;printf("该数的阶乘为:%ld\n",result);}该函数在参数n比较小的时候运行完全正常,但是随着n变大(如,超过12)就出现了问题,结果会溢出而变成意料之外的数据,究其原因,是因为任何基本类型的变量都有一定的表示范围。
要计算更大参数的阶乘,可以使用数组存放阶乘结果,于是有了下面的程序:/* 数的阶乘(改进版)*/#include"stdio.h"main(){int n;printf("请输入一个数:");scanf("%d",&n);jiecheng(n);}int jiecheng(int n){int m,i,j,c,t,a[1000];a[0]=1;m=1;for(i=2;i<=n;i++){for(c=0,j=0;j<m;j++){t=a[j]*i+c;a[j]=t%10;c=t/10;}while(c){a[m++]=c%10;c/=10;}}printf("该数的阶乘为:");for(j=m-1;j>=0;j--)printf("%d",a[j]);printf("\n");}这样一来,就可以计算大数的阶乘了。
用汇编语言计算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进制数。
四、程序流程图五、程序清单data1 segmentinput1 db 'please input the number :','$'input2 db 10,?,10 dup(?) ;输入的16进制数error db 'Out of range','$'output1 db 'The answer is 1','$'output2 db 'The answer is :','$'str1 dw 100 dup(?) ;保存1—N(后一个数覆盖前一个数)str2 dw 7000h dup(?) ;N!乘积的值(1)p dw 100 dup(?) ;上一个乘积的高16位data1 endsdata2 segmentstr3 dw 7fffh dup(?) ;N!乘积的值(2)data2 endscode segmentassume cs:code,ds:data1,es:data2org 100h ;程序从偏移地址100h开始执行start: mov ax,data1 ;程序初始化mov ds,axmov ax,data2mov es,ax ;初始化结束mov ah,9lea dx,input1int 21hmov ah,2 ;回车mov dl,0dhint 21hmov ah,2 ;换行mov dl,0ahint 21hmov ah,0ah ;输入所需求的N值(N为16进制数)lea dx,input2int 21hmov ah,2mov dl,0dhint 21hmov ah,2mov dl,0ahint 21hlea bx,input2mov al,[bx+1] ;判断输入的N值是否超过FFFFH cmp al,4ja s1mov cl,4 ;把输入的N值有ASCH码转成16进制数mov ah,[bx+2]mov al,[bx+3]cmp al,39hja abc1def1: shl al,clcmp ah,39hja abc2def2: shr ax,clmov dh,almov ah,[bx+4]mov al,[bx+5]cmp al,39hja abc3mov cl,4def3: shl al,clcmp ah,39hja abc4def4: shr ax,clmov dl,al ;转换结束mov ax,dx ;判断N值是否为0cmp ax,0jz s2jmp s3abc1: sub al,37hjmp def1abc2: sub ah,37hjmp def2abc3: sub al,37hjmp def3abc4: sub ah,37hjmp def4s1: mov ah,9 ;若N值超过FFFFH的输出lea dx,errorint 21hjmp nexts2: mov ah,9 ;N值为1的输出lea dx,output1int 21hjmp nexts3: mov cx,ax ;计算N的阶乘mov ax,1mov [str1],ax ;N从1开始,作为乘数lea si,str2mov [si],ax ;N!的积从1开始,作为被乘数mov ax,0mov [p],ax ;(n-1)!的乘积的低16位与n相乘后积的高16位mov bx,1 ;开始N!的乘积占一个字空间mov WORD ptr[p+10],0 ;(n-1)!的乘积的高16位与n相乘后积的低16位和(n-1)!的乘积的低16位与n相乘后积的高16位的和的进位,初始进位为0 mov ah,9lea dx,output2int 21hmov ah,2mov dl,0dhint 21hmov ah,2mov dl,0ahint 21hlop2: mov [p+2],bxlop3: mov ax,[si] ;(n-1)!的乘积从最低16位的内容与n相乘mov dx,[str1]mul dxclcadd ax,[p+10] ;前一次的进位与当前乘积的低16位内容相加jnc k1 ;判断是否产生进位mov WORD ptr[p+10],1add ax,[p] ;前一个积的高16位与现在积的低16位相加jmp k2k1: add ax,[p]jnc k3 ;判断是否产生进位mov WORD ptr[p+10],1jmp k2k3: mov WORD ptr[p+10],0k2: mov [si],axmov [p],dxadd si,2dec bxcmp bx,0jnz lop3mov bx,[p+2]clcadd dx,[p+10]cmp dx,0jz re ;判断(n-1)!乘积的最高16位内容与n的乘积的高16位是否为0inc bxmov [si],dxre: mov ax,[str1]cmp ax,9000h ;判断是N!乘积的内容高位部分是否要存到es 中jnc re1jmp re2re1: cmp cx,1ja s4re2: inc WORD ptr[str1] ;乘数增1lea si,str2mov WORD ptr[p],0mov WORD ptr[p+10],0loop lop2dec bxmov cx,bxlop4: add si,2loop lop4inc bxadd bx,bxinc sijmp lop5s4: inc WORD ptr[str1] ;若N的值超过8000h,8000h*8001h*8002h*N mov [p+6],bxmov [p+8],bxlea si,str2lea di,str3mov es:[di],dxmov WORD ptr[p],0mov WORD ptr[p+10],0mov bx,1dec cxlop6: mov [p+4],bxlop7: mov ax,[si]mov dx,[str1]mul dxclcadd ax,[p+10]jnc k4mov WORD ptr[p+10],1add ax,[p]jmp k5k4: add ax,[p] ;前一个积的高16位与现在积的低16位相加,产生进位jnc k6mov WORD ptr[p+10],1jmp k5k6: mov WORD ptr[p+10],0k5: mov [si],axadd si,2mov [p],dxdec WORD ptr[p+6]mov ax,[p+6]cmp ax,0jnz lop7mov ax,[p+8]mov [p+6],axlop8: mov ax,es:[di]mov dx,[str1]mul dxclcadd ax,[p+10]jnc k7mov WORD ptr[p+10],1add ax,[p]jmp k8k7: add ax,[p] ;前一个积的高16位与现在积的低16位相加,产生进位jnc k9mov WORD ptr[p+10],1 jmp k8k9: mov WORD ptr[p+10],0 k8: mov es:[di],axadd di,2mov [p],dxdec bxcmp bx,0jnz lop8mov bx,[p+4]clcadd dx,[p+10]cmp dx,0jz re4inc bxmov es:[di],dxre4: inc WORD ptr[str1] lea si,str2lea di,str3mov WORD ptr[p],0mov WORD ptr[p+10],0 dec cxcmp cx,0jnz lop6dec bxmov cx,bxlop9: add di,2loop lop9inc bxinc dilop10: dec bx ;若N>8000h,输出N!乘积的高位内容mov al,BYTE ptr es:[di]mov ch,almov cl,4shr al,clcmp al,09hja op3add al,30hjmp ip3op3: add al,37hip3: mov ah,2mov dl,alint 21hmov al,chand al,0fhcmp al,09hja op4add al,30hjmp ip4op4: add al,37hip4: mov ah,2mov dl,alint 21hdec dicmp bx,0jnz lop10mov bx,[p+6]dec bxmov cx,bxlop11: add si,2loop lop11inc bxadd bx,bxinc silop5: dec bx ;输出N!的乘积mov al,BYTE ptr [si]mov ch,almov cl,4cmp al,09hja op1add al,30hjmp ip1op1: add al,37hip1: mov ah,2mov dl,alint 21hmov al,chand al,0fhcmp al,09hja op2add al,30hjmp ip2op2: add al,37hip2: mov ah,2mov dl,alint 21hdec sicmp bx,0jnz lop5next: mov ah,1int 21hmov ah,4chint 21hcode endsend start六、程序运行结果与分析若输入的16进制数N为000A(10进制为10),程序运行后输出的N!应为375F00(H)。
汇编语⾔实现阶乘java递归实现阶乘static int fact(int n) {if (n == 0) {return 1;}return fact(n - 1) * n;}public static void main(String[] args) {System.out.println(fact(5));}汇编实现阶乘# 开始递归函数调⽤addiu $sp, $0, 0x10010080 # 初始化栈地址# 压栈⼊参addiu $s0, $0, 5 # n=5sw $s0, 0($sp) # n=5 压栈addiu $sp, $sp, -4 # 栈指针-4jal FACT # 跳转fact函数(FACT只是标志位,并没有函数)跳转地址:a1nopj END # 跳转END,结束nopFACT: # fact函数体# 压栈返回地址sw $ra, 0($sp) # 跳转地址压栈:a1 a2 a3 a4 a5 a6addiu $sp, $sp, -4 # 栈指针-4#读取⼊参lw $s0, 8($sp) # 读取⼊参 n=5 4 3 2 1 0#压栈返回值sw $0, 0($sp) # 返回值压栈(占位)0 0 0 0 0 0addiu $sp, $sp, -4 # 栈指针-4#递归base条件# if (n == 0) { return 1}bne $s0, $0, RECURSION # 如果5!=0则跳转RECURSION 4!=0 3!=0 2!=0 1!=0nop# 读取下返回地址lw $t1, 8($sp) # a6# 出栈:返回值,返回地址addiu $sp, $sp, 8 # 站指针+8# 压栈返回值addiu $s0, $zero, 1 # return 1sw $s0, 0($sp) # 栈 a6->1addiu $sp, $sp, -4 # 栈指针-4jr $t1 # 跳转:a6nopRECURSION : # recursion# return fact(n-1) * n#压栈参数addiu $s1, $s0, -1 # 参数4 (n-1) 3 2 1 0sw $s1, 0($sp) # 参数压栈:4 3 2 1 0addiu $sp, $sp, -4 # 栈指针-4jal FACT # 跳转fact函数跳转地址:a2 a3 a4 a5 a6nop# 现在的栈是什么样⼦的?参数 | 返回地址 | 返回值 | ⼦函数的参数 | ⼦函数的返回值 | 当前SP# 当前参数lw $s0, 20($sp) # 加载参数:1 2 3 4 5# ⼦函数返回值lw $s1, 4($sp) # 返回值 1 1 2 6 24# 返回地址lw $t1, 16($sp) # 返回地址:a5 a4 a3 a2mult $s1, $s0 # 1X1 1x2 2x3 6x4 24x5mflo $s2 # 1x1=1 1x2=2 2x3=6 6x4=24 24x5=120# 出栈:addiu $sp, $sp, 16 # 栈指针+16# 返回值压栈sw $s2, 0($sp) # 栈a5->1 a4->2 a3->6 a2->24 a1->120addiu $sp, $sp, -4 # 栈指针-4jr $t1 # 跳转:a5 a4 a3 a2 a1nopEND:使⽤MARS模拟器编写汇编是完全⾯向过程的语⾔,是CPU指令的可读形式汇编从上往下顺序执⾏,⾼级语⾔中的流程控制语句如if,while等在汇编中就是各种跳转。
实验:递归计算N!
张钰琪 914106840411
一.实验目的
1.掌握子程序设计的方法;
2.输入并汇编求N!程序;
3.观察并记录运行结果。
二.输入并汇编求N!程序1,流程图
N!源程序
STACKSG SEGMENT STACK 'S' ;定义堆栈
DW 128 DUP('ST')
STACKSG ENDS
DATA SEGMENT
N_VAL DW 4 ;定义N值
RESULT DW ? ;结果
DATA ENDS
CODE SEGMENT
ASSUME CS:CODE,DS:DATA,SS:STACKSG FRAME STRUC ;定义帧结构
SAV_BP DW ? ;保存BP值
SAV_CS_IP DW 2 DUP(?) ;保存返回地址
N DW ? ;当前N值
RESULT_ADDR DW ? ;结果地址
FRAME ENDS
MAIN PROC FAR
MOV AX,DATA
MOV DS,AX
LEA BX,RESULT
PUSH BX ;结果地址入栈 PUSH N_VAL ;N值入栈
CALL FAR PTR FACT ;调用递归子程序 MOV CL,10
MOV AX,RESULT
DIV CL
;把阶乘结果转换成十进制数
OR AX,3030H ;转换成ASCII码
MOV DL,AL
MOV AH,2 ;显示结果的高位
INT 21H
MOV AX,RESULT
DIV CL
; 把阶乘结果转换成十进制数
OR AX,3030H ;转换成ASCII码
MOV DL,AH
MOV AH,2 ;显示结果的低位
INT 21H
R1: MOV AX,4C00H
INT 21H
MAIN ENDP
FACT PROC FAR ;N!递归子程序
PUSH BP ;保存BP值
MOV BP,SP ;BP指向帧基地址
PUSH BX
PUSH AX
MOV BX,[BP].RESULT_ADDR
MOV AX,[BP].N ;取帧中N值
CMP AX,0
JE DONE ;N=0时退出子程序嵌套
PUSH BX;为下一次调用压入结果地址
DEC AX
PUSH AX;为下一次调用压入(N-1)值
CALL FAR PTR FACT
R2: MOV BX,[BP].RESULT_ADDR
MOV AX,[BX] ;取中间结果(N-1)!
MUL [BP].N ;N*(N-1)!
JMP SHORT RETURN
DONE: MOV AX,1 ;0!=1
RETURN: MOV [BX],AX ;存中间结果
POP AX
POP BX
POP BP
RET 4
FACT ENDP
CODE ENDS
END MAIN
实验总结
实验内容很复杂并繁琐。
但是通过本次实验,我掌握了子程序的设计方法,掌握了子程序的递归调用方法。
本程序是运用递归调用子程序的方法实现求N!。
我相信通过多次上机练习,反复分析讨论汇编过程的命令操作,对我们的汇编能力还是很有帮助的。