高精度计算,大整数加、减、乘、除、阶乘、阶乘和

大整数运算的来源

常用的数据类型及其表示范围 :
UInt32/unsigned int: 0~4294967295

Int32/int: -2147483648~2147483647

Int64/long long: -9223372036854775807~9223372036854775808

UInt64/unsigned long long:0 ~18446744073709551615

float: -3.4E-38~3.4E+38
double : 1.7E-308~1.7E+308
首先看看python怎么写

a=int(input())
b=int(input())
print(a*b)

唉,流泪

由于c++跟python不一样,它的数据类型范围是有限的,最大能表示的正整数也只有20位,数据再大一些的时候就会发生数据溢出,这时候我们可以借助字符串来进行大整数运算;
1.大整数运算仿照小学加减乘除计算方法(就是手算时在草稿本上的步骤,写代码的时候脑子里时刻想象着这个步骤来写代码),进行模拟运算;
2.大整数加减乘法是借助int数组(或者vector数组)和字符串进行操作,字符串默认没有前导0
3.加减乘每次计算前都将字符串先翻转一下,从最低位开始求
4.加法和乘法最后不需要判断最高位是不是0,减和除需要判断前导0

大整数加法

大整数加法是最简单的
参考代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
int ans[N];
string a,b;
int main()
{
    cin>>a>>b;
    reverse(a.begin(),a.end());  //翻转
    reverse(b.begin(),b.end());
    int lena=a.length();
    int lenb=b.length();
    int i=0;
    int jin=0;
    while(i<lena&&i<lenb)    //a与b相同长度的部分
    {
        int t=a[i]-'0'+(b[i]-'0')+jin;
        ans[i]=t%10;
        jin=t/10;
        i++;
    }
    while(i<lena)
    {
        int t=a[i]-'0'+jin;
        ans[i]=t%10;
        jin=t/10;
        i++;
    }
    while(i<lenb)
    {
        int t=b[i]-'0'+jin;
        ans[i]=t%10;
        jin=t/10;
        i++;
    }
    if(jin) ans[i++]=jin;  //最后还有进位
    for(int j=i-1;j>=0;j--)
    cout<<ans[j];
    return 0;
} 

大整数减法

#include<iostream>
#include<algorithm>
using namespace std;
const int N=100005;
int ans[N];
string a,b;
int main()
{
    cin>>a>>b;
    if(a==b) 
    {
        cout<<0;return 0;
    } 
    if(a.length()<b.length()||(a.length()==b.length()&&a<b))
    {
        cout<<"-";    //a比b小就输出负数
        string t=a;a=b;b=t;
    }//保证a比b大 
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    int lena=a.length();
    int lenb=b.length();
    int i=0;
    int jin=0;
    while(i<lena&&i<lenb)
    {
        int t=(a[i]-'0')-(b[i]-'0')+jin;
        if(t<0)
        {
            t+=10;jin=-1;
        }
        else jin=0;
        ans[i]=t;
        i++;
    }
    while(i<lena) 
    {
        int t=a[i]-'0'+jin;
        if(t<0)
        {
            t+=10;jin=-1;
        }
        else jin=0;
        ans[i]=t;
        i++;
    }
    while(i<lenb)
    {
        int t=b[i]-'0'+jin;
        if(t<0)
        {
            t+=10;jin=-1;
        }
        else jin=0;
        ans[i]=t;
        i++;
    }
    if(jin==-1) ans[i++]--;
    bool f=false;
    for(int j=i-1;j>=0;j--)
    {
        if(ans[j]!=0) f=true;
        if(f) cout<<ans[j];
    }

    return 0;
} 

大整数乘法

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1000005;
int ans[N];
string a,b;
int main()
{
    cin>>a>>b;
    if(a=="0"||b=="0") 
    {
        cout<<0;return 0;
    } 
    reverse(a.begin(),a.end());
    reverse(b.begin(),b.end());
    int lena=a.length();
    int lenb=b.length();
    int ind=0;
    for(int i=0;i<lenb;i++)
    {
        ind=i;
        for(int j=0;j<lena;j++)
        {
            int t=(a[j]-'0')*(b[i]-'0')+ans[ind];
            ans[ind]=t%10;
            ans[ind+1]+=t/10;
            ind++;
        }
    }
    if(ans[ind]!=0) cout<<ans[ind];
    for(int i=ind-1;i>=0;i--)
    cout<<ans[i];

    return 0;
} 

大整数除法

不需要进行字符串的翻转,模拟草稿纸上的计算
被除数用string类型表示,除数默认是小数据,用int型表示
一般不处理高精度除以高精度的问题,复杂度会很高

#include<iostream>
#include<algorithm>
#include<sstream>
using namespace std;
const int N=1000005;
int ans[N];
string a;
int b;
int main()
{
    cin>>a>>b;
    if(a=="0")
    {
        cout<<0<<endl;
        cout<<0<<endl;return 0;
    }
    stringstream ss;  //a有可能比b小,单独考虑
    ss<<b;
    string bi=ss.str();
    if(a.length()<bi.length()||(a.length()==bi.length()&&a<bi))
    {
        cout<<0<<endl;
        cout<<a<<endl; return 0;
    }
    int lena=a.length();
    int achu=0,bchu=0,yushu=0;
    int i=0;
    while(i<lena)   //也是模拟在草稿纸上进行除法运算的过程,主要是b的数值不大,就可以直接做整数之间的除法,就会简单一些
    {
        achu+=a[i]-'0';
        ans[i]=achu/b;
        yushu=achu%b;
        achu=yushu;
        achu*=10;
        i++;   
    }
    bool f=false;
    for(int j=0;j<i;j++)
    {
        if(ans[j]!=0) f=true;
        if(f) cout<<ans[j];
    }
    cout<<endl;
    cout<<yushu<<endl;
    return 0;
} 

大整数阶乘

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int n;
    cin>>n;
    int max=36000;
	int a[max];
	for(int i=0;i<max;i++) 
	   a[i]=0;                  //数组不是默认为0,先要给数组赋值 
	int c;
	a[0]=1;
	int sum;
	for(int i=2;i<=n;i++)     //从2乘到n 
	{
		c=0;
	  	for(int j=0;j<max;j++)
	  	{
	  		sum=a[j]*i+c;    //乘积加进位 
	  		a[j]=sum%10;
	  		c=sum/10;
		  }
	 }
	bool flag=false;
	 for(int l=max-1;l>=0;l--)
	 {
	 	if(!flag)
	 	{
	 		if(a[l]>0)
	 		{
	 			flag=true;
	 			cout<<a[l];
			 }
		 }
		 else cout<<a[l];
	 }
  	 return 0;  
 } 

大整数阶乘和

阶乘和是利用一个临时数组进行阶乘,然后利用大整数加法累加到结果数组里面

#include<bits/stdc++.h>
using namespace std;
const int ma=100;  // int max=100;
int ans[ma];
int jc[ma];
void leijia()   //大整数加法
{
	int up=0;
	for(int i=0;i<ma;i++)
	{
		int temp=ans[i]+jc[i]+up;
		up=temp/10;
		ans[i]=temp%10;
	}
}
int main()
{
	int n;cin>>n;
	jc[0]=1;
	for(int k=1;k<ma;k++)
	jc[k]=0;
	memset(ans,0,sizeof(ans));
	int up;
	for(int k=1;k<=n;k++)
	{
		jc[0]=1;
		for(int m=1;m<ma;m++)
		jc[m]=0;	
		for(int i=k;i>=1;i--)
		{
			up=0;
			for(int j=0;j<ma;j++)
			{
				int temp=jc[j]*i+up;
				jc[j]=temp%10;
				up=temp/10;	
			}
		}
	leijia();
}

	bool flag=true;
	for(int i=ma-1;i>=0;i--)
	{
		if(ans[i]!=0||!flag)
		{
			flag=false;
			cout<<ans[i];
		}
	}
	return 0;
 } 

其中一个因子不是很大

在大整数的加减乘除等方法中是将两个因子都看成了字符串来表示,但是在实际做题的过程中可能会出现以下两种情况,可以对上面的算法进行稍微的改进

  1. x +、-、*、/ y,但是y用int或者long long能够表示的情况,这时候就只需要将x用字符串表示,y直接保持原来的数据类型就行
  2. 如果题目对算法的时间复杂度要求只能是O(n),将x和y都看成字符串的情况(主要是乘法)需要两重循环,这时候基本上题目也隐含了y是可以直接保持原来的数据类型不变的,外层循环只需要遍历一边x的每一位,对每一位进行加减乘除y(对于除法运算一般都默认y是整数了,不然复杂度会很高)
    参考代码如下(乘法):
string cheng(string a,int b)
{
	if(a=="0"||b==0) return "0";
	int lena=a.length();
	int now=0; 
	vector<int>ans;
	for(int ai=lena-1;ai>=0;ai--)  //当a还没结束 
	{
		now+=(a[ai]-'0')*b;
		ans.push_back(now%10);
		now/=10;  //进位 
	}
	while(now)
	{
		ans.push_back(now%10);
		now/=10;
	}
	
	//去掉前导0 
	string res="";
	for(int i=ans.size()-1;i>=0;i--) 	res+=(ans[i]+'0');
	return res;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值