【汇编】汇编实现求大数阶乘问题

36 篇文章 0 订阅
3 篇文章 0 订阅

开发环境

Windows 10 专业版

开发工具

Microsoft Visual Studio Community 2017版本15.9.12

测试结果是否正确的网站
https://zh.numberempire.com/factorialcalculator.php

主要思路

   大数乘法思路参考:

C++代码实现

#include<iostream>
#include<vector>
using namespace std;

int MAXNUM = INT_MAX / 9;//因为我们第23行使用int类型保存inputnum * ResultArr[n] 这里需要对inputnum范围做出限制
						//约定ResultArr[n] 的最大值为9 所以 inputnum最大值就是 INT_MAX/9

bool factorial(vector<int> &res)
{
	int TotalCount = 1;//存放当前ResultArr的有效位数
	res.push_back(1);//1和0的阶乘均等于1,所以我们先初始化结果数组

	int inputnum = 0;//保存用户输入的数字
	cout << "请输入的需要求的数的阶乘";
	cin >> inputnum;
	if (inputnum > MAXNUM)
	{
		cout << "输入的数字超出本程序可以求解的范围" << endl;
		return false;
	}
	if (inputnum < 0)
	{
		cout << "输入的数字无法求解阶乘" << endl;
		return false;
	}
	int Begin = 2;//从求2的阶乘开始计算
	int carry = 0;//上次计算的进位
	for (; Begin <= inputnum; ++Begin)
	{
		int i = 0;
		while (i <= res.size() - 1)
		{
		   //因为这里需要从ResultArr的第0位开始每一位有效位和Begin求之后相关结果保存在ResultArr
			int tmpRe = Begin * res[i] + carry;
			res[i] = tmpRe % 10;//保存当前的结果的个位数
			carry = tmpRe /= 10;//更新carry
			i++;
		}
		while (carry != 0)
		{
			res.push_back(carry % 10);
			//res[TotalCount++] = carry % 10;
			carry /= 10;
		}
	}
}
int GetTailZeroCount(vector<int> &res)
{
	vector<int>::iterator it = res.begin();
	int totalcount = 0;
	for (; it != res.end(); ++it)
	{
		if (*it == 0)
			++totalcount;
		else
			break;
	}
	return totalcount;
}
void PrintfRes(vector<int> &res)
{
	for (vector<int>::reverse_iterator it = res.rbegin(); it != res.rend();)
		cout << *it++;
	cout << endl;
}
int main()
{
	vector<int> res;
	if (factorial(res))
	{
		PrintfRes(res);
		cout << "阶乘结果的总位数为:" << res.size()<<endl;
		cout << "尾数0的个数为" << GetTailZeroCount(res) << endl;
	}
	return 0;
}

汇编代码

include vcIO.inc

.data
     infoMsg byte '请输入你要求的阶乘',13,10,0
	 errorMsg byte '你输入的阶乘小于0',13,10,0
	 NoneMsg byte '输入的n无法求阶乘',13,10,0
	 zeroMsg byte '尾数0的个数为',13,10,0
	 total byte '总位数为',13,10,0
	 inputnum dword 0;存放要求阶乘的数字
	 bufferNum dword 100000 dup (0),0;;存放结果的数组长度为100000可以根据需求进行适量的更改
	 arrayNum dword 1;;存放结果数组有效数字的个数;打印时候需要以其作为度量打印出来
	 carry dword 0;;存放进位
	 n_format byte '%d',0
	 str_return byte '|',10,0
.code
main proc
	pushad
Start:
	mov eax,1
	mov bufferNum[0],eax
	pushad
	invoke printf,offset infoMsg
	popad
	invoke scanf,offset n_format,offset inputnum;
	mov eax,inputnum
	cmp eax,0
	jl None;输入的数小于0结束程序给出提示
	mov ebx,2;用于判断所求阶乘的值,如果这个值小于2(0,1)那么结果是1
;;开始(外部循环)
Outer:
;;如果当前ebx大于inputnum这个用户输入进来的数据那么这个阶乘求解完毕
	cmp ebx,inputnum;;ebx和inputnum比较如果ebx大于inputnum证明当前求解完毕
	jg Finish;完成计算,
	;;
	mov ecx,1

	mov eax,0
	mov carry,eax;;默认第0位的所要加的进位为0
;;主要作用计算一个"大数"和一个数字的"乘积"
Deal_mul:
	cmp ecx,arrayNum;;arrayNum的值代表的就是当前结果字符串的长度
	jg Deal_carry;当前

	mov eax,ebx;;当前的数字类型的变量存放在ebx中(也是需要和字符数组乘的数字)
	mul bufferNum[ecx*4-4];;将eax*bufferNum[ecx*4-4];存放在eax中
	add eax,carry;;给结果加上进位
	
	push ebx;;保存当前ebx的值即为当前数字变量的值
	mov ebx,0ah;;除法运算
	div ebx
	pop ebx
	mov bufferNum[ecx*4-4],edx;;余数保存在当前结果数组中
	mov carry,eax;;除数放在carry中更新carry这个数字
	inc ecx;;存放当前操作的下标位置
	jmp Deal_mul
;;可能存在处理完成之后还有carry中
Deal_carry:
	cmp carry,0
	jz Deal_next;;如果等于0直接求解下次的乘法运算
	mov eax,1
	add arrayNum,eax;下标
	mov edx,0
	mov eax,carry;;把进位数字记录下来
	push ebx
	mov ebx,0ah
	div ebx;;使用eax(carry) 除 ebx(10) 即个位数的值 
	pop ebx;;将当前数字弹出来
	push edx;;将余数保存进去
	mov eax,arrayNum;;下标
	push ebx;;将当前数字压栈
	mov ebx,04h;;
	mul ebx;;eax * 4
	pop ebx
	sub eax,4
	pop edx
	mov bufferNum[eax],edx;保存余数到数组
	mov edx,0
	mov eax,carry
	push ebx
	mov ebx,0ah
	div ebx
	pop ebx
	mov carry,eax
	jmp Deal_carry;循环保存余数直到进位只剩个位
Deal_next:
;;每次给ebx++跳回去接着求阶乘
	inc ebx
	jmp Outer
;;arrayNum记录的就是结果字符串的长度,也就是要打印的结果的长度
Finish:
	mov ecx,arrayNum
;;打印结果
PrintRs:
	cmp ecx,0
	jle End_P;
	mov eax,bufferNum[ecx*4-4]

	pushad
	invoke printf,offset n_format,eax
	popad

	xor eax,eax;;每次打印完成给eax清零操作
	dec ecx
	jmp PrintRs
	
;;本次输入的n无法求解阶乘
None:
	pushad
	invoke printf,offset NoneMsg
	popad
End_P:
	invoke printf,offset str_return

	invoke printf,offset total

	mov eax,arrayNum;
	invoke printf,offset n_format,eax

	mov edi,0;
	mov ecx,1
;;求解末尾0的个数
Zero:
	mov eax,bufferNum[ecx*4-4]
	cmp eax,0
	jne Print_zero
	inc edi
	inc ecx
	cmp ecx,arrayNum
	jge End_p
	jmp Zero
Print_zero:
	pushad
	invoke printf,offset str_return
	invoke printf,offset zeroMsg
	popad

	invoke printf,offset n_format,edi
End_p:
	popad
	ret
main endp
end main

 

  • 5
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值