【8086汇编】N!计算实验

本文介绍了一个使用16位寄存器实现的阶乘计算程序。程序接收用户输入的数值N(0~65535),并利用内存缓冲区进行大数阶乘计算,结果以16进制形式输出。实验难点在于处理超出寄存器容量的大数运算,通过将部分结果存储在内存缓冲区中,并迭代进行两字相乘来解决。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、实验内容

编写计算N!的程序。数值N由键盘输入,结果在屏幕上输出,N的范围为0~65535,即刚好能被一个16位寄存器容纳。

二、实验说明

编制附乘程序的难点在于随着N的增大,其结果远不是寄存器所能容纳。这就必须把结果放在一个内存缓冲区中。然而乘法运算只能限制于两个字相乘,因此要确定好算法,依次从缓冲区中取数,进行两字相乘,并将DX中的高16位积作为产生的进位。

程序根据阶乘的定义:N!=N×(N-1)×(N-2)×……×2×1,从左入右依次计算,结果先将BP初始化为存放N值,然后使BP-1,以后BP依次减1,直至变化为1.每次让BP与BUF中的字单元按由低到高的次序相乘,低位结果AX仍保存在相应的BUF字单元中,最高位结果DX则进到进位单元CY中,以作为高字单元相乘时从低字来的进位,初始化CY=0,计算结果的长度随着乘积运算而不断增长,由字单元LEN指示。当最高字单元与BP相乘时,若DX不为0,则结果长度要扩展。

三、实验流程图

在这里插入图片描述

四、实验程序

CRLF MACRO
	MOV AH,02H
	MOV DL,0DH
 	INT 21H
 	MOV AH,02H
 	MOV DL,0AH
 	INT 21H
ENDM

DATAS SEGMENT
	MES1 DB 'Please input number N','$'
   	MES2 DB 'The result is: $'
   	BUF DW 256 DUP (0)
    	LEN DW 1
    	CY DW ?
DATAS ENDS

STACKS SEGMENT
	DW 32 DUP(?)
STACKS ENDS

CODES SEGMENT
	ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
	MOV AX,DATAS
	MOV DS,AX

	MOV AH,9   			 ;显示提示
	LEA DX,MES1
	INT 21H
	CRLF

	CALL GETNUM   			 ;DX中存放读到的键盘输入值
	MOV BP,DX   			 ;N值送BP
	CMP BP,0
	JZ L4  				 ;BP=0跳转
	CMP BP,1
	JZ L4
	LEA SI,BUF  			  ;SI指向BUF首址
    	MOV [SI],DX			  ;缓冲区初始化值为键盘输入N
D1: 	DEC BP     			  ;BP-1=1跳转
 	CMP BP,1
 	JZ L5
 	XOR BX,BX       		  ;BX清0,每次相乘从最低位开始
   	MOV WORD PTR CY,0  		  ;同时CY每次要清零
    	MOV CX,LEN    			  ;CX送循环,判断占了多少个子单元,循环多少次
D2: 	MOV AX,[SI+BX]    
    	MUL BP
    	ADD AX,CY   			  ;加低位进位
    	JNC D3   			  ;结果无进位跳转
    	INC DX   			  ;有进位,积高位加进位
D3: 	MOV [SI+BX],AX  		  ;存低位
 	MOV CY,DX  			  ;高位保存在CY,乘高位单元时加上
 	INC BX
 	INC BX   			  ;一个字长度
	LOOP D2
	CMP DX,0   			  ;判断DX两次运算后是否为0     
 	JZ D1      			  ;DX高位为0跳D1
 	INC WORD PTR LEN    		  ;DX高位不为0则长度加1,DX送下一个单元
 	MOV [SI+BX],DX
 	JMP D1


L4: 	MOV SI,OFFSET BUF  		  ;BUF存1
 	MOV WORD PTR [SI],1 
L5: 	MOV AH,09H     			  ;显示MES2单元内容
 	MOV DX,OFFSET MES2
 	INT 21H
 	MOV CX,LEN
 	MOV BX,CX    			  ;BX=BUF长度
 	DEC BX      			  ;BX-1
 	SHL BX,1
L6: 	MOV AX,[SI+BX]
 	CALL DISPLAY1    		  ;从高位显示结果
 	DEC BX
 	DEC BX
 	LOOP L6

	MOV AH,4CH
    	INT 21H
    	
GETNUM PROC NEAR

 	XOR DX,DX
L1: 	MOV AH,1
 	INT 21H
 	CMP AL,0DH
 	JZ L2

	CMP AL,40H
 	JL L3      			 ;小于跳转
 	SUB AL,07H 
L3: 	SUB AL,30H

	MOV CL,04H
 	SHL DX,CL
 	XOR AH,AH       
 	ADD DX,AX      
 	JMP L1
L2: 	PUSH DX
 	CRLF 
 	POP DX      
 	RET
 	
GETNUM ENDP 

DISPLAY1 PROC NEAR

	PUSH BX
 	PUSH CX
 	PUSH DX
 	PUSH AX
	MOV AL,AH
 	CALL DISPLAY2
 	POP AX
 	CALL DISPLAY2
 	POP DX
 	POP CX
	POP BX
	
 	RET 	
DISPLAY1 ENDP

DISPLAY2 PROC NEAR     			;显示字符(AL)

	MOV BL,AL
 	MOV DL,BL       		;执行MOV AH,02,AX=0200
 	MOV CL,04      			;执行CALL调用,AL=30H
 	SHR DL,CL
	CALL DISPLAY3      		;显示高位
 	MOV DL,BL
 	AND DL,0FH
 	CALL DISPLAY3      		;显示低位
 	
 	RET
DISPLAY2 ENDP

DISPLAY3 PROC NEAR      		;显示一位(DL=0XH)

	ADD DL,30H
 	CMP DL,3AH
 	JB A1
 	ADD DL,07H
A1: 	MOV AH,02H
 	INT 21H
 	
 	RET
DISPLAY3 ENDP

CODES ENDS
    	END START

五、实验现象

在这里插入图片描述

六、实验小结

①、在使用CALL调用子程序时,系统会给AL赋30H,所以在DISPLAY2中第一句MOV BL,AL不可或缺。
②、D1中BX,CY每次要清0,不可以省略。
③、输入要是4位,0000~FFFF,输出是16进制。
④、一开始读键盘输入的值的想法是,用十进制数读入,高位键值乘10,在加上低位键值,按这方法依次读低位。程序用的是读入十六进制数,先读高位,左移四位,在读低位。这两种方法都可以使用,且效果一样,计算机保存的内容都是一样的,都是某个数的二进制(PS:用十进制数读入的话,读入的是BCD码,但是保存的话是以二进制保存的),但是显示的话用十六进制显示会很方便。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值