定义
由于C语言的数据类型能存放的数字大小有一定的限制。
如整型int表达范围是(
−
2
31
-2^{31}
−231~
2
31
−
1
2^{31}-1
231−1)
无符号整数unsigned long是(0~
2
32
−
1
2^{32}-1
232−1)
浮点型double只能提供15~16位的有效数字。
因此,在计算位数超过十几位的数时,不能采用现有的数据类型,只能自己编程计算。
高精度算法(High Accuracy Algorithm)是处理大数字的数学计算方法。在一般的科学计算中,会经常算到小数点后几百位或者更多,当然也可能是几千亿几百亿的大数字。一般这类数字我们统称为高精度数,高精度算法是用计算机对于超大数据的一种模拟加,减,乘,除,乘方,阶乘,开方等运算。对于非常庞大的数字,我们将这个数字拆开,存放在一个数组里作为一个数字,这样的数就被称为是高精度数。高精度算法就是能处理高精度数各种运算的算法。
本文只简单介绍最基本的高精度操作。
输入与预处理
我们输入的数字远超long long等c语言基本数据类型的表示范围,因此我们要把输入的数据作为字符类型数组读取进我们的程序里。
此外,为了方便进行计算(对齐个位、方便处理进位),我们还需要把读取进来的数组逆序放进一个int数组里。相应的,输出也应逆序。
代码如下。
#include <stdio.h>
#include <string.h>
struct asdf{
int n,x[1001];
};
char A[1001];
void change(char *A,asdf *a)
{
(*a).n=strlen(A);
for (int i=0;i<(*a).n;++i)
(*a).x[(*a).n-i]=A[i]-'0';
}
void Scan(asdf *a)
{
memset((*a).x,0,sizeof((*a).x));
scanf("%s",A);
change(A,a);
}
void Print(asdf a)
{
for (int i=a.n;i;--i) printf("%d",a.x[i]);
}
int main()
{
asdf a;
Scan(&a);
Print(a);
}
高精加
思想
用竖式计算7685+3419。
流程![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/df063f8b293d2d956a3cff8bab25db53.png)
代码
#include <stdio.h>
#include <string.h>
struct asdf{
int n,x[1001];
};
char A[1001];
void change(char *A,asdf *a)
{
(*a).n=strlen(A);
for (int i=0;i<(*a).n;++i)
(*a).x[(*a).n-i]=A[i]-'0';
}
void Scan(asdf *a)
{
memset((*a).x,0,sizeof((*a).x));
scanf("%s",A);
change(A,a);
}
void Print(asdf a)
{
for (int i=a.n;i;--i) printf("%d",a.x[i]);
}
asdf Plus(asdf a,asdf b)
{
asdf ans;
ans.n=(a.n>b.n?a.n:b.n); //和的长度不小于任一加数的长度
for (int i=1;i<=a.n||i<=b.n;i++) //ans的每一位都等于两加数该位之和加进位
ans.x[i]=a.x[i]+b.x[i]+ans.x[i-1]/10,ans.x[i-1]%=10;
if (ans.x[ans.n]>10) ans.x[ans.n]%=10,ans.x[++ans.n]=1;
return ans;
}
int main()
{
asdf a,b;
Scan(&a); //调用输入并预处理函数
Scan(&b);
asdf ans=Plus(a,b); //调用求和函数
Print(ans); //调用输出函数
}
高精减
思想
用竖式计算7685-3419。
流程![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/64bc402a64e57c2fc7f8c76012c50bb2.png)
代码
#include <stdio.h>
#include <string.h>
struct asdf{
int n,x[1001],f;
};
char A[1001];
void change(char *A,asdf *a)
{
(*a).n=strlen(A);
for (int i=0;i<(*a).n;++i)
(*a).x[(*a).n-i]=A[i]-'0';
}
void Scan(asdf *a)
{
(*a).f=1;
memset((*a).x,0,sizeof((*a).x));
scanf("%s",A);
change(A,a);
}
void Print(asdf a)
{
if (a.f<0) printf("-");
for (int i=a.n;i;--i) printf("%d",a.x[i]);
}
int Compare(asdf a,asdf b)
{
if (a.n<b.n) return 1;
if (a.n>b.n) return 0;
for (int i=1;i<=a.n;++i)
if (a.x[i]<b.x[i]) return 1;
else if (a.x[i]>b.x[i]) return 0;
return 0;
}
asdf Minus(asdf a,asdf b)
{
asdf ans;
if (Compare(a,b))//如果小数减大数就返回-(b-a)
{
ans=Minus(b,a);
ans.f=-1;
return ans;
}
ans.n=(a.n>b.n?a.n:b.n);//和的长度不大于被减数的长度
for (int i=1;i<=ans.n;++i) ans.x[i]=a.x[i]-b.x[i];
for (int i=1;i<ans.n;++i)//处理借位
if (ans.x[i]<0) ans.x[i]+=10,ans.x[i+1]--;
while (ans.x[ans.n]==0&&ans.n>1) ans.n--;//去前导零
return ans;
}
int main()
{
asdf a,b;
Scan(&a); //调用输入并预处理函数
Scan(&b);
asdf ans=Minus(a,b); //调用求和函数
Print(ans); //调用输出函数
}
高精乘单精
思想
不使用竖式,计算128712*2。
流程![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ef1afad1ce0f7a4d1ec995e917e0b474.png)
代码
#include <stdio.h>
#include <string.h>
struct asdf{
int n,x[1001],f;
};
char A[1001];
void change(char *A,asdf *a)
{
(*a).n=strlen(A);
for (int i=0;i<(*a).n;++i)
(*a).x[(*a).n-i]=A[i]-'0';
}
void Scan(asdf *a)
{
(*a).f=1;
memset((*a).x,0,sizeof((*a).x));
scanf("%s",A);
change(A,a);
}
void Print(asdf a)
{
if (a.f<0) printf("-");
for (int i=a.n;i;--i) printf("%d",a.x[i]);
}
asdf Times(asdf a,int b)
{
asdf ans;
ans.n=a.n;
int x=0;
for (int i=1;i<=ans.n;++i)
{
ans.x[i]=a.x[i]*b+x;
x=ans.x[i]/10;
ans.x[i]%=10;
}
while (x) ans.x[++ans.n]=x%10,x/=10;
return ans;
}
int main()
{
asdf a;
int b;
Scan(&a); //调用输入并预处理函数
scanf("%d",&b);
asdf ans=Times(a,b); //调用求和函数
Print(ans); //调用输出函数
}
高精乘高精
思想
用竖式计算542*768。
流程
代码
#include <stdio.h>
#include <string.h>
struct asdf{
int n,x[5001];
};
char A[5001];
void change(char *A,asdf *a)
{
(*a).n=strlen(A);
for (int i=0;i<(*a).n;++i)
(*a).x[(*a).n-i]=A[i]-'0';
}
void Scan(asdf *a)
{
memset((*a).x,0,sizeof((*a).x));
scanf("%s",A);
change(A,a);
}
void Print(asdf a)
{
for (int i=a.n;i;--i) printf("%d",a.x[i]);
}
asdf Times(asdf a,asdf b)
{
asdf ans;
int x=0;
memset(ans.x,0,sizeof(ans.x));
ans.n=a.n+b.n-1; //和的长度不小于两乘数长度之和减一
for (int i=1;i<=a.n;++i)
for (int j=1;j<=b.n;++j) ans.x[i+j-1]+=a.x[i]*b.x[j];
for (int i=1;i<=ans.n;i++)
ans.x[i]+=x,x=ans.x[i]/10,ans.x[i]%=10;
while (x) ans.x[++ans.n]=x%10,x/=10;
while (ans.x[ans.n]==0&&ans.n>1) ans.n--;
return ans;
}
int main()
{
asdf a,b;
Scan(&a); //调用输入并预处理函数
Scan(&b);
asdf ans=Times(a,b); //调用求和函数
Print(ans); //调用输出函数
}