一、简介
在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加、减、乘、除、乘方、阶乘、开方等运算。 对于一个很大的数字N >= 10^ 100,很显然这样的数字无法在计算机中正常存储。于是, 我们想到了办法,将这个数字拆开,拆成一位一位的或者是四位四位的存储到一个数组中,用一个数组去表示一个数字。这样这个数字就被称谓是高精度数。 对于高精度数,也要像平常数一样做加减乘除以及乘方的运算,于是就有了高精度算法。
二、高精度加法
读小学时我们做加法都采用竖式方法,从小到大每位数逐位相加,大于10的进位。这里采用的就是这种方法。
#include <bits/stdc++.h>
using namespace std;
char at[105],bt[105];
int a[105],b[105],c[105];
int main()
{
cin>>at;
cin>>bt;
//将数a从小位到大位逐个储存在数组a中
for(int i=0;i<strlen(at);++i)
a[i+1]=at[strlen(at)-i-1]-'0';
int lena=strlen(at);
//将数b从小位到大位逐个储存在数组b中
for(int i=0;i<strlen(bt);++i)
b[i+1]=bt[strlen(bt)-i-1]-'0';
int lenb=strlen(bt);
//a+b的结果储存在c数组中
int lenc=1;
int yu=0;
while(lenc<=lena||lenc<=lenb)
{
//本位的计算结果为两数此位之和加上前面位数多出来的进位
c[lenc]=a[lenc]+b[lenc]+yu;
//多出来的进位
yu=c[lenc]/10;
c[lenc]%=10;
lenc++;
}
c[lenc]=yu; //最后可能还有进位
if(c[lenc]==0)
lenc--;
for(int i=lenc;i>=1;--i)
cout<<c[i];
cout<<endl;
return 0;
}
三、高精度减法
类似加法这里是竖式减法,从小到大逐位相减,不够的向前借1,但有一点要注意被减数要比减数大,否则交换两数位置,最后结果前输出一个负号。
#include <bits/stdc++.h>
using namespace std;
//a-b
char at[105],bt[105],tmp[105];
int a[105],b[105],c[105];
int main()
{
cin>>at;
cin>>bt;
//如果a<b,输出负号,交换a和b的位置
if(strlen(at)<strlen(bt)||(strlen(at)==strlen(bt)&&strcmp(at,bt)<0))
{
strcpy(tmp,at);
strcpy(at,bt);
strcpy(bt,tmp);
cout<<"-";
}
//将数a从小位到大位逐个储存在数组a中
for(int i=0;i<strlen(at);++i)
a[i+1]=at[strlen(at)-i-1]-'0';
int lena=strlen(at);
//将数b从小位到大位逐个储存在数组b中
for(int i=0;i<strlen(bt);++i)
b[i+1]=bt[strlen(bt)-i-1]-'0';
int lenb=strlen(bt);
int lenc=1;
while(lenc<=lena||lenc<=lenb)
{
//本位不够向上一位借一
if(a[lenc]<b[lenc])
{
a[lenc]+=10;
a[lenc+1]-=1;
}
c[lenc]=a[lenc]-b[lenc];
lenc++;
}
//把前置所有为0的位舍去 但至少留一个0(a=b的情况)
while(c[lenc]==0&&lenc>1)
lenc--;
for(int i=lenc;i>=1;--i)
cout<<c[i];
cout<<endl;
return 0;
}
四、高精度乘法
类似加法,也可以用竖式求乘法。在做乘法运算时,同样也有进位,同时对每一位进行乘法运算时,必须进行错位相加。
每一位的计算c[i+j-1]+=a[i]*b[j]+yu
。
#include <bits/stdc++.h>
using namespace std;
char at[105],bt[105];
int a[105],b[105],c[210];
int main()
{
cin>>at;
cin>>bt;
int lena=strlen(at);
for(int i=0;i<lena;++i)
a[i+1]=at[lena-i-1]-'0';
int lenb=strlen(bt);
for(int i=0;i<lenb;++i)
b[i+1]=bt[lenb-i-1]-'0';
int yu=0;
for(int i=1;i<=lena;++i)
{
yu=0;
//用a的i位逐个乘以b的每一位
for(int j=1;j<=lenb;++j)
{
c[i+j-1]+=a[i]*b[j]+yu; //加上上一位运算多出来的
yu=c[i+j-1]/10; //多出来的进位
c[i+j-1]%=10;
}
c[i+lenb]+=yu;
}
int lenc=lena*lenb;
while(c[lenc]==0&&lenc>1) //删去前导0
lenc--;
for(int i=lenc;i>=1;--i)
cout<<c[i];
cout<<endl;
return 0;
}
五、高精度除法
1、高精除以低精
高精除以低精,采用的是按位相除法,从大位到小位高精的每一位除以低精,不够的移到下一位运算。
#include <bits/stdc++.h>
using namespace std;
char at[105];
int a[105],b,c[105];
int main()
{
cin>>at;
cin>>b;
//将数a从大位到小位逐个储存在数组a中
int lena=strlen(at);
for(int i=0;i<lena;++i)
a[i+1]=at[i]-'0';
int yu=0;
for(int i=1;i<=lena;++i)
{
c[i]=(yu*10+a[i])/b; //上一位剩下的乘10再加上本位
yu=(yu*10+a[i])%b; //取出本次运算剩下的
}
int lenc=1;
while(c[lenc]==0&&lenc<lena) //删去前导0
lenc++;
for(int i=lenc;i<=lena;++i)
cout<<c[i];
cout<<endl;
return 0;
}
2、高精除以高精
高精除以高精是高精度算法中实现最复杂的,采用的是减法模拟除法,对被除数的每一位都减去除数。
如989除以12,我们可以用989一次次减去12,但逐个相减效率太慢。我们可以直接用989-12*10,相当于减去10次了,也就相当于98-12。代码也是基于这个思想实现。
#include <bits/stdc++.h>
using namespace std;
char at[105],bt[105];
int a[105],b[105],c[105];
int compare(int a[],int b[])//比较a、b,若a>b为1;若a<b为-1;若a=b为0
{
int i;
if(a[0]>b[0])
return 1;
if(a[0]<b[0])
return -1;
for(i=a[0];i>0;i--)//从高位到低位比较
{
if(a[i]>b[i])
return 1;
if(a[i]<b[i])
return -1;
}
return 0;
}
int main()
{
cin>>at>>bt;
a[0]=strlen(at);//a[0]存储串1的位数
b[0]=strlen(bt);//b[0]存储串2的位数
for(int i=1;i<=a[0];i++)
a[i]=at[a[0]-i]-'0';
for(int i=1;i<=b[0];i++)
b[i]=bt[b[0]-i]-'0';
int temp[105];
c[0]=a[0]-b[0]+1;
for(int i=c[0];i>0;i--)
{
memset(temp,0,sizeof(temp));
for(int j=1;j<=b[0];j++)//从i开始的地方,复制数组b到数组temp
temp[j+i-1]=b[j];
temp[0]=b[0]+i-1;
while(compare(a,temp)>=0)//用减法模拟
{
c[i]++;
int flag=compare(a,temp);
if(flag==0)
a[0]=0;
else if(flag==1)
{
for(int j=1;j<=a[0];++j)
{
if(a[j]<temp[j])
{
a[j]+=10;
a[j+1]--;
}
a[j]-=temp[j];
}
while(a[0]>0&&a[a[0]]==0)
a[0]--;
}
}
}
while(c[0]>0&&c[c[0]]==0)//删除前导0
c[0]--;
cout<<"商为:";
if(c[0]<=0)//输出结果
cout<<0<<endl;
else
{
for(int i=c[0];i>0;i--)
cout<<c[i];
cout<<endl;
}
cout<<"余数为:";
if(a[0]==0)//输出余数
cout<<0<<endl;
else
{
for(int i=a[0];i>0;i--)
cout<<a[i];
cout<<endl;
}
return 0;
}