算法学习-高精1-高精度加法和高精度减法
整数的高精度加、减法的实现
由于屑C++不自带高精,所以常常无法处理一些大数的运算。最近我学习了高精度,将所学内容整理于此。其实是为了应付这周五的学习笔记。(我刚接触C++,也是第一次用博客,,如果有什么错误请多多包涵,,)
- 为什么要用高精度?
因为long long最大也只能存20位的数,强行输入大数会爆 掉。
- 那要怎么实现高精度计算?
那就用用字符数组或string类存储大数,然后根据小学生加减法原理进行加减乘除,得出结果。
接下来先对最简单的高精度加法进行实现。
整数的高精度加法 (负数见减法部分)
先从离我们最近的入手:小学生加法原理
我们计算\(a_1b_1c_1d_1+b_2c_2d_2\)时,先是个位\(d_1+d_2\),满\(10\)进\(1\),可以理解为满\(10\),就让\(d_1+d_2\)的结果减去\(10\),记为个位,下一次计算\(c_1+c_2\)时就同时加上一个\(1\),如果满\(10\)同上操作,记为十位。如果都不满\(10\),那就不减\(10\)也不进\(1\)。其他依次往前推。
这样我们就不难得出整个算法的核心:
c for (i=0;i<=c3;++i)
{
c[i]+=a1[i]+a2[i]; //a1,a2用来储存两个相加的数
c[i+1]=c[i]/10; //进位的实现
c[i]=c[i]%10;
}
那具体要怎么实现?
输入部分不必多说,输入后我们必须先知道两个字符数组的最长的长度,由此来知道进行加法的最高位数,这也是字符数组的便利所在:
c1=strlen(s1);
c2=strlen(s2);
len=max(c1,c2);
之后将字符数组逆序赋值给整型数组,为什么呢?()
for (i=0;i<c1;++i)
a1[i]=s1[c1-1-i]-'0';//要减去个‘0’
for(i=0;i<c2;++i)
a2[i]=s2[c2-1-i]-'0';
之后就可以进行加法啦!
for (i=0;i<=len;++i)//这里len为什么要用等号?
{
c[i]+=a1[i]+a2[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;
}
然后逆序输出,记得删除前导0
if (c[len]==0) --len;//删除前导0
for (i=len;i>=0;--i)
cout<<c[i];
这样就大工造成啦!
附上我自己第一次做时候的代码:
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
char s1[505]={0},s2[505]={0};
int a1[505]={0},a2[505]={0},c[506]={0};
int i=0,c1=0,c2=0,c3=0;
cin>>s1>>s2;
c1=strlen(s1);
c2=strlen(s2);
c3=max(c1,c2);
for (i=0;i<c1;++i)
a1[i]=s1[c1-1-i]-'0';
for(i=0;i<c2;++i)
a2[i]=s2[c2-1-i]-'0';
for (i=0;i<=c3;++i)
{
c[i]+=a1[i]+a2[i];
c[i+1]=c[i]/10;
c[i]=c[i]%10;
}
if (c[c3]==0)
{
for (i=c3-1;i>=0;--i)
cout<<c[i];
}
else
{
for (i=c3;i>=0;--i)
cout<<c[i];
}
return 0;
}
接下来是小学生减法(结果负数也得输出,以下用string做答)
也先从原理入手:
嘛,,竖式减法,如果\(\ a_1b_1c_1d_1-b_2c_2d_2\),先个位相减,也就是\(\ d1-d2\),若小于\(\ 0\),则让\(\ c_1\)减去\(\ 1\),再把\(\ d1+d2\)加上10,记为个位,然后进行\(\ c_1-c_2\),如果结果大于\(\ 0\),就直接记为十位,再进行\(\ b_1-b_2\),依次往前推。
这样可以得出:
for (i=0;i<lim;++i)//lim为两个数中最高位的位数
{
ans[i]+=arr1[i]-arr2[i];
if (ans[i]<0)
{
--ans[i+1];
ans[i]+=10;
}
}
我用 --ans[i+1] 来实现退位。
然而这只是应付arr1中存的数比arr2中大的情况,那么:
当arr1<arr2时,用swap进行交换,并用 bool flag 记录结果正负
if (( n1=str1.size())==(n2=str2.size())&&str1<str2||n1<n2)
{
str1.swap(str2);//保证str1>=str2
flag=1;
}
这样就可以随意进行任意整数的加减了,其余部分基本与加法一致。
搭嘎!删除前导0这里有坑:
- 和加法不一样,减法的最高位数可能是多个0,可以用循环进行删除:
while (ans[lim-1]==0) lim--;
- 如果结果等于 0 ,则要特殊考虑:
if (lim-1<0) cout<<0;
贴代码:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int main()
{
string str1,str2;
int n1=0,n2=0,lim=0,i=0;//n用来存字符串长度
bool flag=0;
int arr1[10500]={0},arr2[10500]={0},ans[10500]={0};
cin>>str1>>str2;
if (( n1=str1.size())==(n2=str2.size())&&str1<str2||n1<n2)
{
str1.swap(str2);//保证str1>=str2
flag=1;
}
n1=str1.size();
n2=str2.size();
for (i=n1-1;i>=0;--i) arr1[n1-1-i]=str1[i]-'0';
for (i=n2-1;i>=0;--i) arr2[n2-1-i]=str2[i]-'0';
lim=max(n1,n2);
for (i=0;i<lim;++i)
{
ans[i]+=arr1[i]-arr2[i];
if (ans[i]<0)
{
--ans[i+1];
ans[i]+=10;
}
}
while (ans[lim-1]==0) lim--;
if (flag==true) cout<<'-';
if (lim-1<0) cout<<0;
for (i=lim-1;i>=0;--i)
cout<<ans[i];
return 0;
}
顺带一提,我之前用字符数组实现高精减法的是这个的2倍长
写完之后感觉格式好乱,,,
高精度减法的实现我参考了这个
别人说的蛮详细的,,不像我,,很多地方都懒得解释