高精度算法(数组实现)(数组的效率能比Vector高一倍)
一.高精度加法
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 200+4; //根据题目的最大值。+4为了防止A+B出现进位
char s1[MAXN] = {};//存储字符串
char s2[MAXN] = {};//存储字符串
int a[MAXN] = {};//存储加数A
int b[MAXN] = {};//存储加数B
int c[MAXN] = {};//存储和B
int main() {
scanf("%s %s", s1, s2);//读入字符串A
//将字符串写入到数组A中
int len1 = strlen(s1);
for (int i=0; i<len1; i++) {
//倒序写入
a[i] = s1[len1-i-1] - '0';
}
//将字符串写入到数组A中
int len2 = strlen(s2);
for (int i=0; i<len2; i++) {
//倒序写入
b[i] = s2[len2-i-1] - '0';
}
//模拟竖式加法
int jw=0;//进位
int len = max(len1, len2)+1;//注意因为最高位可能出现进位
for (int i=0; i<len; i++) {
c[i] = a[i] + b[i] + jw;//当前加数A位数据+加数B位位数据+上一位的进位
jw = c[i] / 10;//本次加法是否存在进位
c[i] %= 10;//只能保存 0 ~ 9 的数据
}
//删除前导零
for (int i=len-1; i>=0; i--) {
//因为我们是从索引 0 开始,所以最高位是保存在 len-1
if (0==c[i] && len>1) {
//注意要有 len>1 这个条件。考虑特殊情况,加法结果为 00,我们实际要输出 0。
len--;
} else {
//第一个不是零的最高位,结束删除
break;
}
}
//逆序打印输出
for (int i=len-1; i>=0; i--) {
printf("%d", c[i]);
}
printf("\n");
return 0;
}
二.高精度减法
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
using namespace std;
const int maxn = 50010;
int a[maxn],b[maxn],c[maxn];
string s1,s2;
bool pd = false; //s1<s2为false
int len1,len2,len;
//高精度减法 s1 - s2
int main()
{
cin >> s1 >> s2;
len1 = s1.length();
len2 = s2.length();
//s1-s2,判断s1和s2的大小,如果s1<s2,交换s1,s2,并标记pd=true,最后输出负号
if(len1 < len2 || (len1 == len2 && s1 < s2))//字符串比较大小从索引0开始逐位比较
{
swap(s1,s2);
pd = true;
len1 = s1.length();
len2 = s2.length();
}
//将字符串信息录入数组
for(int i=len1-1,j=0;i>=0;i--,j++)
a[j] = s1[i] - '0';
for(int i=len2-1,j=0;i>=0;i--,j++)
b[j] = s2[i] - '0';
//
// cout << "/数组/" << endl;
// for(int i=0;i<len1;i++)
// cout << a[i];
// cout << endl;
// for(int i=0;i<len2;i++)
// cout << b[i];
// cout << endl;
// cout << "/数组/" << endl;
//
//模拟竖式减法
len = max(len1,len2);
for(int i=0;i<len;i++)
{
if(a[i] < b[i]) // 向高出借位
{
a[i+1] --;
a[i] += 10;
}
c[i] = a[i] - b[i];
}
//删除前导零
for(int i=len-1;i>=0;i--)
{
if(c[i] == 0 && len > 1)
len--;
else
break;
}
//输出,有负号先输出负号
if(pd)
cout << "-";
for(int i=len-1;i>=0;i--)
cout << c[i];
cout << endl;
return 0;
}
三.高精度乘法
在除法算式中,除号后面的数叫做除数,除号前面的数叫做被除数
前导零的产生:例如在214/3中,因为2/3=0,所以在数组的首位放上0,由此产生前导零
去前导零,i从len开始,例如5*5=25,答案需要2个长度,但是分配时只给了1+1-1=1个长度,所以长度要加1 ,因此输出时也从len开始而不是len-1
#include<iostream>
#include<cmath>
#include<string>
using namespace std;
const int maxn = 50010;
int a[maxn],b[maxn],c[maxn];
int len1,len2,len;
string s1,s2;
int main()
{
cin >> s1 >> s2;
//特判
if(s1=="0" || s2=="0")
{
cout << 0;
return 0;
}
//初始化
len1 = s1.length();
len2 = s2.length();
for(int j=0,i=len1-1;i>=0;i--,j++)
a[j] = s1[i] - '0';
for(int j=0,i=len2-1;i>=0;i--,j++)
b[j] = s2[i] - '0';
//竖式相乘
len = len1 + len2 - 1;
for(int i=0;i<len;i++)
{
for(int j=0;j<=i;j++)
c[i] += a[j] * b[i-j];
//进位
if(c[i] > 9)
{
c[i+1] += c[i]/10;
c[i] %= 10;
}
}
//去前导零
for(int i=len;i>=0;i--)
{
if(c[i]==0 && len>1)
len--;
else
break;
}
//逆序输出
for(int i=len;i>=0;i--)
cout << c[i];
cout << endl;
return 0;
}
四.高精度除法
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
const int N=1e5;
string s;
long long int b;
long long int ans[N],a[N];
int main()
{
cin>>s>>b; //a是被除数 b是除数
int len=s.length();
for(int i=0;i<len;i++)
a[i+1]=s[i]-'0'; //反序存储
long long int tmp=0; //所有中间的数都用longlong
for(int i=1;i<=len;i++)
{
a[i]+=tmp*10; //累计前面剩的数
ans[i]=a[i]/b; //如果不够除,因为都是整形数,就是0
tmp=a[i]-ans[i]*b; //计算剩下的数
}
int i;
for(i=1;i<len;i++)
if(ans[i]!=0) //除0
break;
for(;i<=len;i++)
cout<<ans[i]; //输出
return 0;
}
五.阶乘之和
题目链接:P1009 [NOIP1998 普及组] 阶乘之和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
#include<iostream>
#include<cstdio>
using namespace std;
int n,a[101]={0},s[101]={0};
//每一次的阶乘都是在上一次阶乘的基础上乘x,可以减少运算,提高效率
void multi(int x)
{
int g=0;
for(int i=100;i>=0;i--)
{
a[i]=a[i]*x+g;
g=a[i]/10;
a[i]=a[i]%10;
}
}
void sum()
{
int g=0;
for(int i=100;i>=0;i--)
{
s[i]=s[i]+a[i]+g;
g=s[i]/10;
s[i]=s[i]%10;
}
}
void out()
{
int w;
for(int i=0;i<=100;i++)
{
if(s[i]!=0)
{
w=i;
break;
}
}
for(int i=w;i<=100;i++)
printf("%d",s[i]);
}
int main()
{
scanf("%d",&n);
s[100]=a[100]=1;
for(int i=2;i<=n;i++)
{
multi(i); //求i的阶乘和
sum(); //将i的阶乘和加到结果数组s
}
out();
return 0;
}
六.大数取模
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char ch[1100];
int main()
{
int n;
while(scanf("%s%d",ch,&n)!=EOF)
{
int len,i,sum=0;
len=strlen(ch);
for(i=0;i<len;i++) //模板
sum=(sum*10+(ch[i]-'0'))%n;
cout<<sum<<endl;
}
return 0;
}