此文参考自:https://blog.csdn.net/hacker00011000/article/details/51298294
他的快排也很好:三种快排四种优化
这里暂时有大数加法、大数减法、大数阶乘,其他的以后补上:
https://blog.csdn.net/y990041769/article/details/20116995
大数相加
1、从结尾开始每位相加
2、两个整数长度不相等(肯定有一个已经加完了,再把没有加完的加上去)
3、最高位有进位,要再进一位
4、结果字符串逆序大数相乘
分析
12*34=?
乘数:12
被乘数:34
1、先把乘数列出来,第i行列左起第i位数,列N次(N为乘数的位数)
第二行起每次右移一位
(1) (1)
(2) (2)
2、写入被乘数,按先列后行的方式
(1,3) (1,4)
(2,3) (2,4)
3、将()内的数两乘
(1,3=3) (1,4=4)
(2,3=6) (2,4=8)
4、相加,注意进位
(1,3=3) (1,4=4)
(2,3=6) (2,4=8) -------------------------
3 10 8
. -------------------------
4 0 8
12*34=408
再看三位数乘法
123*456=?
第一步:
(1) (1) (1)
(2) (2) (2)
(3) (3) (3)
第二步:
(1,4) (1,5) (1,6)
(2,4) (2,5) (2,6)
(3,4) (3,5) (3,6)
第三步:
(1,4= 4) (1,5= 5) (1,6= 6)
(2,4= 8) (2,5=10) (2,6=12)
(3,4=12) (3,5=15) (3,6=18)
第四步:
(1,4= 4) (1,5= 5) (1,6= 6)
(2,4= 8) (2,5=10) (2,6=12)
(3,4=12) (3,5=15) (3,6=18) ----------------------------------------------
4 13 28 27 18
. . . . ----------------------------------------------
5 6 0 8 8
123*456=56088
分析一下每一位的值是如何计算出来的,以下说的位都是从个位算起:
结果的第i位,是乘数的第i位乘以被乘数的1位,再加上乘数的第i-1位乘以被乘数的第2位,一起加到乘数的第1位乘以被乘数的第i位。
这样描述起来有点不明白,画个图就很清楚了:
123*456的第3位:从乘数的第3位(1)起到第1位(3),按从右向左的方式
逐个乘以被乘数:
1*6+2*5+3*4=28
再把进位加上就可以了。
即:计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0)))。等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i 。然后相加再加上前一位的进位,就是结果的第i位
到这里,已经可以得出一个通用的计算方法,把结果逐位计算出来。
通过上面的分析,我们知道了算法的核心思想,接下来就能把算法实现
#include <iostream>
#include <sstream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
//C++大数相加
string BigNumAdd(const string& strNum1, const string& strNum2)
{
string strSum;
int len1 = strNum1.size()-1;
int len2 = strNum2.size()-1;
int bit = 0; //保存进位
//从结尾开始每位相加
while (len1>=0 && len2>=0)
{
//求每位的和(要把进位也加上)
int tmpSum = strNum1[len1]-'0' + strNum2[len2]-'0' + bit;
//保存进结果
strSum += tmpSum % 10 + '0';
//求进位
bit = tmpSum / 10;
--len1;
--len2;
}
//两个整数长度不相等(肯定有一个已经加完了,不需要再额外加if来判断,因为while就可以判断)
while (len1 >= 0)
{
//和上个while循环一样
int tmpSum = strNum1[len1]-'0' + bit;
strSum += tmpSum % 10 + '0';
bit = tmpSum / 10;
--len1;
}
while (len2 >= 0)
{
//和上个while循环一样
int tmpSum = strNum2[len2]-'0' + bit;
strSum += tmpSum % 10 + '0';
bit = tmpSum / 10;
--len2;
}
//最高位有进位
if (bit != 0)
strSum += bit + '0';
//反转
reverse(strSum.begin(), strSum.end());
return strSum;
}
//C++大数相乘
string BigNumMultiply(const string& strNum1, const string& strNum2)
{
string strMultiply;
//两数相乘最大有m+n位
int bit = 0;
int len1 = strNum1.size()-1;
int len2 = strNum2.size()-1;
//计算每一位
for (int i=0; i<len1+len2+2; ++i)
{
//计算结果的第i位(权值肯定为i,第1位也就是个位权值为0(pow(10, 0)))
//等于乘数的第(i~0)位分别与被乘数的第(0~i)位相乘,因为这样每位相乘之后权值仍为i
//然后相加再加上前一位的进位,就是结果的第i位
//然后%10得出第i位,/10得到进位
int tmp = 0;
for (int j=i; j>=0; --j)
{
//如果下标超出字符串的范围 j为num1的下标, i-j为num2的下标,然后两数相乘
if (j>len1 || (i-j)>len2)
continue;
//还要注意字符串数字的最高位在字符串的最低位所以得用len减去
tmp += (strNum1[len1-j]-'0') * (strNum2[len2-(i-j)]-'0');
}
//加上进位
tmp += bit;
//为了防止最后一位是0,但是却加上了
if (tmp == 0 && i == len1+len2+1)
break;
//求余得到结果的第i位
strMultiply += tmp % 10 + '0';
//计算新的进位
bit = tmp / 10;
}
//判断结果的最后一个字符如果是0的话说明可以删去
//if (strMultiply[strMultiply.size()-1] == '0')
// strMultiply[strMultiply.size()-1] = '\0';
//反转
reverse(strMultiply.begin(), strMultiply.end());
return strMultiply;
}
int main()
{
string str1;
string str2;
cin >> str1 >> str2;
//相加和相乘
cout << BigNumAdd(str1, str2) << endl;
cout << BigNumMultiply(str1, str2) << endl;
int n;
cin >> n;
//阶乘
string rlt("1");
string opNum;
for (int i=1; i<=n; ++i)
{
//ss不可以定义在for循环外
stringstream ss;
ss << i;
ss >> opNum;
rlt = BigNumMultiply(rlt, opNum);
}
cout << rlt << endl;
return 0;
}
输入:
123111111111
45622222222
5
输出:
168733333333
5616602469103375308642
120