高精度算法(数组实现)(数组的效率能比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;
} 

参考文章:高精度高精度乘法(C++)_是饿梦啊的博客-CSDN博客_c++高精度乘法


四.高精度除法

#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;
}

参考文章:(10条消息) 高精度除法_蒟蒻本蒻的博客-CSDN博客

五.阶乘之和

题目链接: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;
}

 参考文章:(12条消息) 大数取余算法的证明及实现_serene的博客-CSDN博客_大数取余


posted @ 2022-05-05 08:42  光風霽月  阅读(57)  评论(0编辑  收藏  举报