C++高精度算法
本人刚开始学习c++,在洛谷网站刷题时遇到用高精度算法计算阶乘之和P1009时遇到了困惑,于是学习了这种算法,以此记录自己的学习过程。
高精度算法存在的必要性
我们有时在用c++做运算时,例如50!,数据的运算结果超出了int、double、long long、undesigned long long的范围,使数据溢出,这时便需要高精度算法来解决。
高精度算法
基本原理
此处为我的个人理解,勿喷。
基本原理就是将一个大数的个位、十位、百位等有序地存储在一个整型数组中,然后通过操作整型数组来进行按位运算
高精度加法
大体思路
参考小学学习的竖式运算的法则,个位与个位相加,超过10进1,十位与十位相加,超过10进1,此时不要忘记个位时的进位,以此类推。
正常情况下,例如123,百位数字1对应a[0],数字的最高位对应数组的最小下标,由于考虑到进位的影响,这样就会导致在运算时很不方便,因此就可以用倒序存储的方式使数字的最低位对应数组的最小下标,即个位数字3对应a[0]。
代码
倒叙的代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
int a[1000] = {}, b[1000] = {}, c[2000] = {};//a[1000],b[1000]分别用来存储倒序后的数字
string a1, b1;
cin >> a1 >> b1;//将两个数字以字符串的形式输入
int m = max(a1.length(), b1.length());//用来接收相加后的长度,如果最高位有进位,m还需+1
for (int i = 0; i < a1.length(); i++)//倒叙的代码
{
a[a1.length() - 1 - i] = a1[i]-'0';
}
for (int i = 0; i < b1.length(); i++)
{
b[b1.length() - 1 - i] = b1[i]-'0';
}
高精度加法代码,接上。
for (int i = 0; i < max(a1.length(), b1.length()); i++)//高精度加法的核心代码
{
c[i] += a[i] + b[i];//按位相加
c[i + 1] = c[i] / 10;//判断有无进位,有进位的话,c[i+1]+=1;
c[i] %= 10;//判断取余后c[i]的最终结果
}
if (c[max(a1.length(), b1.length())] != 0)//用来判断相加后的总长度是否增加
m++;
for (int i=m - 1; i >= 0; i--)//完成后再倒序输出,即为最终结果
{
cout<<c[i];
}
return 0;
}
高精度乘法
大体思路
与加法有相似之处,按位相乘,但是需要注意的是不同位相乘对结果的作用不一样,需要通过举例子找下下标的规律。另外还有一点不同就是加法的进位最多就是1,而乘法则不一定。
代码
倒序代码
#include<iostream>
#include<string>
using namespace std;
int main()
{
int a[1000] = {}, b[1000] = {}, c[2000] = {};//a[1000],b[1000]分别用来存储倒序后的数字
string a1, b1;
cin >> a1 >> b1;//将两个数字以字符串的形式输入
int n = a1.length()+ b1.length();//两个数相乘最终的位数不会超过两数的位数之和
for (int i = 0; i < a1.length(); i++)//倒序的主要代码
{
a[a1.length() - 1 - i] = a1[i]-'0';
}
for (int i = 0; i < b1.length(); i++)
{
b[b1.length() - 1 - i] = b1[i]-'0';
}
高精度乘法代码,接上。
for (int i = 0; i < a1.length(); i++)//核心部分:首先按位相乘,暂时不进位,与加法有所差别
{
for (int j = 0; j < b1.length(); j++)
{
c[i + j] += a[i] * b[j];//找下标之间的关系十分重要
}
}
for (int i = 0; i < n; i++)//按位相乘后对进位进行处理,本位若大于等于10将商加到下一位,余数则作为新的本位
{
if (c[i] >= 10)
{
c[i + 1] += c[i] / 10;
c[i] %= 10;
}
}
while (c[n] == 0)//除去多余的前导
{
n--;
}
for (int i = n; i >= 0; i--)//倒序输出即为所得
{
cout << c[i];
}
return 0;
}
阶乘之和的代码
题目的链接在文章的开头处,代码如下。
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
int n;
int a[100], b[100];
memset(a, 0, sizeof(a));//对数组赋初值
memset(b, 0, sizeof(b));
a[0] = 1;
b[0] = 1;
int i, j;
cin >> n;
for ( i = 2; i<=n ; i++)
{
for ( j = 0; j < 100; j++)//高精度乘法
a[j] *= i;
for ( j = 0; j < 100; j++)
{
if (a[j] >= 10)
{
a[j + 1]+= a[j] / 10;
a[j] %= 10;
}
b[j] += a[j];//高精度加法
if (b[j] >= 10)
{
b[j + 1]+=1;
b[j] -= 10;
}
}
}
for (j = 99; j >= 0; j--)
{
if (b[j])
{
break;
}
}
for (i = j; i >= 0; i--)
{
cout << b[i];
}
system("pause");
return 0;
}