大数乘法 阶乘
比如50的阶乘结果是65位, 而 int 的范围是 10 ^ 9, long long 的范围是 10 ^ 18
- 由于运算结果已经远远超出计算机能表达的范围了,因此衍生出模拟笔算乘法, 并且使用数组, 来保存运算结果的方法
大数乘法
思路
模拟笔算乘法, 如图

由于我们对笔算乘法已经了然于心, 因此几乎不用思考就能算出结果, 但是如果我们慢下来一步一步思考, 我们可以发现一些规律
- 计算乘法时, 每次都是拿 23 的一位数, 与 123 相乘, 相乘次数是 2 次, 即 23 的位数;
- 而拿3 或 2 与 123 相乘时, 相乘次数是3, 即123的位数;
- 计算加法时, 每次都需要向左偏移一位
发现这些规律后, 可以发现
- 第 1 步是一个大循环, 循环次数为 23 即第二个数的位数
- 第 2 步和第 3 步, 是内部的小循环, 循环次数分别是, 123 即第一个数的位数, 和 23 的位数减一
开始动手
代码实现
模拟笔算乘法
为了方便, 我从下标 0 开始处理数据, 读取后需要逆转一下数据, 所以我先使用字符数组(即字符串)读取数据, 处理后在转移到整形数组
#include<iostream>#include<algorithm>#include<cstring>using namespace std;#define Int(x) (x - '0')int main() {int num1[105] = {0}, num2[105] = {0}, ret[205] = {0};char n1[105], n2[105];scanf("%s%s", n1, n2);//这几步只是单纯方便读取及逆序处理int len1 = strlen(n1), len2 = strlen(n2);reverse(n1, n1 + len1);reverse(n2, n2 + len2);for (int i = 0; i < len1; i++) {num1[i] = Int(n1[i]);}for (int i = 0; i < len2; i++) {num2[i] = Int(n2[i]);}//模拟笔算乘法int carry;int t[100], temp;int tlen, offset = 0, rlen;for (int i = 0; i < len2; i++) { //笔算乘法 次数为第二个数的位数carry = 0; //此处为乘法进位memset(t, 0, sizeof(t)); //临时数组每次使用前都需要清零tlen = 0;for (int j = 0; j < len1; j++) {//每次拿出第二个数的一个数 与 第一个数相乘 次数为第一个数的位数temp = num1[j] * num2[i] + carry;t[tlen++] = temp % 10;carry = temp / 10;}if (carry) {t[tlen++] = carry;}carry = 0; //此处为加法进位rlen = offset; //偏移位 笔算中每次向左偏移一位 因为在这里逆序保存 所以变成向右偏移一位for (int i = 0; i < tlen; i++) {temp = ret[i + offset] + t[i] + carry;ret[i + offset] = temp % 10;carry = temp / 10;rlen++;}if (carry) {ret[rlen++] = carry;}offset++;}for (int i = rlen - 1; i >= 0; i--) {cout << ret[i];}cout << endl;return 0;}
运行结果

大数阶乘
思路
既然大数乘法我们都解决, 那么大数阶乘也是相同思路, 每次都是两个数相乘, 不过要注意的是, 我这里输入的数据是在 int 范围内的, 所以就不用使用字符串来保存乘数, 只需要一个数据来保存结果即可
代码实现
#include <iostream>using namespace std;int main() {int a[20001];//储存每一位所得到的数int temp,digit,n;//temp每次的得数 digit每次得数的位数int carry;cin >> n;a[0] = 1;//从1开始乘digit = 1;//位数从第一位开始for (int i = 2; i <= n; i++) {carry = 0;for (int j = 0; j < digit; j++) {temp = a[j] * i + carry;//将一个数的每一位数都分别乘以i,a[j] = temp % 10;carry = temp/10;}//处理进位//此时由于不像大数乘法那样两个数都是个位数相乘//有可能是多位数乘单位数, 所以进位不止一位//需要循环处理进位, 一直到进位为0while (carry) {a[digit] = carry % 10;carry = carry / 10;digit++;}}for (int i = digit-1; i >= 0; i--)//倒序输出每一位printf("%d", a[i]);printf("\n");return 0;}
运行结果

