开发环境
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