在这里,我们约定,能用int表示的数据视为单精度,否则为高精度。所有函数的设计均采用带返回值的形式。
本文包含
1.高精度加法
2.高精度减法
3.高精度乘法
1)高精度乘高精度的朴素算法
2)高精度乘高精度FFT优化算法
3)高精度乘单精度
4.高精度除法
1)高精度除高精度
2)高精度除单精度
5.高精度取模
1)高精度对高精度取模
2)高精度对单精度取模
6.高精度阶乘
7.高精度幂
8.高精度GCD
9.高精度进制转换
10.高精度求平方根
下面切入正题
1.高精度加法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相加再还原。
算法复杂度:o(n)
#include
#include
#include
using namespace std;
const int L=110;
string add(string a,string b)//只限两个非负整数相加
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;ilb?la:lb;
for(int i=0;i=0;i--) ans+=na[i]+'0';
return ans;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相减再还原。
算法复杂度:o(n)
#include
#include
#include
using namespace std;
const int L=110;
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;ilb?la:lb;
for(int i=0;i0) ;lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<
1)高精度乘高精度的朴素算法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o(n^2)
#include
#include
#include
using namespace std;
const int L=110;
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
string s;
int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
for(int i=1;i<=La;i++)
for(int j=1;j<=Lb;j++)
nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
for(int i=1;i<=La+Lb;i++)
nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
for(int i=La+Lb-1;i>=1;i--)
s+=nc[i]+'0';//将整形数组转成字符串
return s;
}
int main()
{
string a,b;
while(cin>>a>>b) cout<
2)高精度乘高精度FFT优化算法
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:将两个高精度乘数每个数位上的数视为多项式对应的系数,用o(n*log(n))的复杂度转成点值形式,再利用o(n)的复杂度相乘,最后对点值进行差值,用o(n*log(n))的复杂度还原成多项式的形式,即原来的形式。
算法复杂度:o(n*log(n))
#include
#include
#include
#include
#include
#include
传入参数约定:传入第一个参数为string类型,,第二个参数为int型,返回值为string类型
算法思想:倒置相乘,然后统一处理进位,再还原。
算法复杂度:o(n)
#include
#include
#include
using namespace std;
const int L=100005;
int na[L];
string mul(string a,int b)//高精度a乘单精度b
{
string ans;
int La=a.size();
fill(na,na+L,0);
for(int i=La-1;i>=0;i--) na[La-i-1]=a[i]-'0';
int w=0;
for(int i=0;i=0) ans+=na[La--]+'0';
return ans;
}
int main()
{
string a;
int b;
while(cin>>a>>b) cout<
4.高精度除法
1)高精度除高精度
传入参数约定:传入第一第二个参数均为string类型,第三个为int型,返回值为string类型
算法思想:倒置,试商,高精度减法。
算法复杂度:o(n^2)
#include
#include
#include
using namespace std;
const int L=110;
int sub(int *a,int *b,int La,int Lb)
{
if(La=0;i--)
if(a[i]>b[i]) break;
else if(a[i]=0;i--)
if(a[i]) return i+1;//返回差的位数
return 0;//返回差的位数
}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
string s,v;//s存商,v存余数
int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
if(La=0;i--)//将除数扩大10^t倍
if(i>=t) b[i]=b[i-t];
else b[i]=0;
Lb=La;
for(int j=0;j<=t;j++)
{
int temp;
while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
{
La=temp;
r[t-j]++;
}
}
for(i=0;i=0) s+=r[i--]+'0';
//cout<
while(i>=0) v+=a[i--]+'0';
if(v.empty()) v="0";
//cout<>a>>b) cout<
1)高精度除单精度
传入参数约定:传入第一参数为string类型,第二个为int型,返回值为string类型
算法思想:模拟手工除法。
算法复杂度:o(n)
#include
#include
using namespace std;
string div(string a,int b)//高精度a除以单精度b
{
string r,ans;
int d=0;
if(a=="0") return a;//特判
for(int i=0;i>a>>b)
{
cout<
5.高精度取模
1)高精度对高精度取模(以在高精度除高精度中实现,此处不再赘述)
2)高精度对单精度取模
传入参数约定:传入第一参数为string类型,第二个为int型,返回值为string类型
算法思想:利用(a+b)%c=a%c+b%c。
算法复杂度:o(n)
#include
#include
using namespace std;
int mod(string a,int b)//高精度a除以单精度b
{
int d=0;
for(int i=0;i>a>>b)
{
cout<
6.高精度阶乘
传入参数约定:传入参数为int型,返回值为string类型
算法思想:高精度乘单精度的简单运用。
算法复杂度:o(n^2)
#include
#include
#include
using namespace std;
const int L=100005;
int a[L];
string fac(int n)
{
string ans;
if(n==0) return "1";
fill(a,a+L,0);
int s=0,m=n;
while(m) a[++s]=m%10,m/=10;
for(int i=n-1;i>=2;i--)
{
int w=0;
for(int j=1;j<=s;j++) a[j]=a[j]*i+w,w=a[j]/10,a[j]=a[j]%10;
while(w) a[++s]=w%10,w/=10;
}
while(!a[s]) s--;
while(s>=1) ans+=a[s--]+'0';
return ans;
}
int main()
{
int n;
while(cin>>n) cout<
7.高精度幂
传入参数约定:传入第一参数为string类型,第二个为int型,返回值为string类型
算法思想:FFT高精乘+二分求幂。
算法复杂度:o(n*log(n)*log(m))
#include
#include
#include
#include
#include
#include
8.高精度GCD
传入参数约定:传入参数均为string类型,返回值为string类型
算法思想:高精度加减乘除的运用。
算法复杂度:已无法估计。
#include
#include
#include
using namespace std;
const int L=110;
string add(string a,string b)
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;ilb?la:lb;
for(int i=0;i=0;i--) ans+=na[i]+'0';
return ans;
}
string mul(string a,string b)
{
string s;
int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
for(int i=1;i<=La;i++)
for(int j=1;j<=Lb;j++)
nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
for(int i=1;i<=La+Lb;i++)
nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
for(int i=La+Lb-1;i>=1;i--)
s+=nc[i]+'0';//将整形数组转成字符串
return s;
}
int sub(int *a,int *b,int La,int Lb)
{
if(La=0;i--)
if(a[i]>b[i]) break;
else if(a[i]=0;i--)
if(a[i]) return i+1;//返回差的位数
return 0;//返回差的位数
}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
string s,v;//s存商,v存余数
int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
if(La=0;i--)//将除数扩大10^t倍
if(i>=t) b[i]=b[i-t];
else b[i]=0;
Lb=La;
for(int j=0;j<=t;j++)
{
int temp;
while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
{
La=temp;
r[t-j]++;
}
}
for(i=0;i=0) s+=r[i--]+'0';
//cout<
while(i>=0) v+=a[i--]+'0';
if(v.empty()) v="0";
//cout<>a>>b) cout<
9.高精度进制转换
传入参数约定:传入第一个参数为string类型,第二第三均为int型,返回值为string类型
算法思想:模拟手工进制转换。
算法复杂度:o(n^2)。
#include
#include
using namespace std;
//将字符串表示的10进制大整数转换为m进制的大整数
//并返回m进制大整数的字符串
bool judge(string s)//判断串是否为全零串
{
for(int i=0;i>s)
{
cout<
10.高精度求平方根,思路就是二分+高精度加减乘除法
设数的长度为n,则需二分log(2,10^n)次即n*log(2,10) 约等于n*3.3,由于数的长度为n,朴素高精度乘法复杂度为o(n^2)。故朴素算法求解高精度平方根复杂度为O(n^3)
当然,你也可以用FFT优化下高精度乘法。
下面的代码实现了求大整数平方根的整数部分。
JAVA版
import java.io.*;
import java.math.*;
import java.util.*;
public class Main {
static Scanner cin = new Scanner (new BufferedInputStream(System.in));
public static BigInteger BigIntegerSqrt(BigInteger n){
BigInteger l=BigInteger.ONE,r=n,mid,ans=BigInteger.ONE;
while(l.compareTo(r)<=0){
mid=l.add(r).divide(BigInteger.valueOf(2));
if(mid.multiply(mid).compareTo(n)<=0){
ans=mid;
l=mid.add(BigInteger.ONE);
}else{
r=mid.subtract(BigInteger.ONE);
}
}
return ans;
}
public static void main(String args []){
BigInteger n;
int t;
t= cin.nextInt();
while(t > 0)
{
t--;
n=cin.nextBigInteger();
BigInteger ans=BigIntegerSqrt(n);
System.out.println(ans);
}
}
}
C++版
#include
#include
#include
#include
using namespace std;
const int L=2015;
string add(string a,string b)//只限两个非负整数相加
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;ilb?la:lb;
for(int i=0;i=0;i--) ans+=na[i]+'0';
return ans;
}
string sub(string a,string b)//只限大的非负整数减小的非负整数
{
string ans;
int na[L]={0},nb[L]={0};
int la=a.size(),lb=b.size();
for(int i=0;ilb?la:lb;
for(int i=0;i0) ;lmax++;
for(int i=lmax-1;i>=0;i--) ans+=na[i]+'0';
return ans;
}
string mul(string a,string b)//高精度乘法a,b,均为非负整数
{
string s;
int na[L],nb[L],nc[L],La=a.size(),Lb=b.size();//na存储被乘数,nb存储乘数,nc存储积
fill(na,na+L,0);fill(nb,nb+L,0);fill(nc,nc+L,0);//将na,nb,nc都置为0
for(int i=La-1;i>=0;i--) na[La-i]=a[i]-'0';//将字符串表示的大整形数转成i整形数组表示的大整形数
for(int i=Lb-1;i>=0;i--) nb[Lb-i]=b[i]-'0';
for(int i=1;i<=La;i++)
for(int j=1;j<=Lb;j++)
nc[i+j-1]+=na[i]*nb[j];//a的第i位乘以b的第j位为积的第i+j-1位(先不考虑进位)
for(int i=1;i<=La+Lb;i++)
nc[i+1]+=nc[i]/10,nc[i]%=10;//统一处理进位
if(nc[La+Lb]) s+=nc[La+Lb]+'0';//判断第i+j位上的数字是不是0
for(int i=La+Lb-1;i>=1;i--)
s+=nc[i]+'0';//将整形数组转成字符串
return s;
}
int sub(int *a,int *b,int La,int Lb)
{
if(La=0;i--)
if(a[i]>b[i]) break;
else if(a[i]=0;i--)
if(a[i]) return i+1;//返回差的位数
return 0;//返回差的位数
}
string div(string n1,string n2,int nn)//n1,n2是字符串表示的被除数,除数,nn是选择返回商还是余数
{
string s,v;//s存商,v存余数
int a[L],b[L],r[L],La=n1.size(),Lb=n2.size(),i,tp=La;//a,b是整形数组表示被除数,除数,tp保存被除数的长度
fill(a,a+L,0);fill(b,b+L,0);fill(r,r+L,0);//数组元素都置为0
for(i=La-1;i>=0;i--) a[La-1-i]=n1[i]-'0';
for(i=Lb-1;i>=0;i--) b[Lb-1-i]=n2[i]-'0';
if(La=0;i--)//将除数扩大10^t倍
if(i>=t) b[i]=b[i-t];
else b[i]=0;
Lb=La;
for(int j=0;j<=t;j++)
{
int temp;
while((temp=sub(a,b+j,La,Lb-j))>=0)//如果被除数比除数大继续减
{
La=temp;
r[t-j]++;
}
}
for(i=0;i=0) s+=r[i--]+'0';
//cout<
while(i>=0) v+=a[i--]+'0';
if(v.empty()) v="0";
//cout<>t;
while(t--)
{
cin>>n;
n=DeletePreZero(n);
cout<