无符号高精度整数
Zhangxm2012 · · 科技·工程
前言
FFT 部分请移步群友 Amidst 的专栏 (二)。
回归正题
这里实现了一个代码长度较小、效率较高的无符号高精度整数,以静态数组为背景。
:::info[Code]
//Code by Zhangxm2012 https://www.luogu.com.cn/user/1426124
#include<iostream>
#include<vector>
#include<cmath>
#include<cstring>
#include<climits>
#define ll long long
#define ull unsigned long long
#define Exit(str,val) {cout<<str;exit(val);}
#define MLE "Memory Limit Exceeded"
#define lf double
#define llf long double
#ifdef ONLINE_JUDGE
#define Re_val 0
#define Div_val 0
#else
#define Re_val 3221225477
#define Div_val 3221225620
#endif
#ifdef SIZE
#define LENGTH SIZE
#else
#define LENGTH 10000
#endif
using namespace std;
namespace IO{
static const int BUFSIZE=1<<20;
char ibuf[BUFSIZE],*is=ibuf,*it=ibuf,obuf[BUFSIZE];int cnt=0;
inline void flush(){
fwrite(obuf,1,cnt,stdout),cnt=0;
return;
}
inline char get(){
if(is==it) it=(is=ibuf)+fread(ibuf,1,BUFSIZE,stdin);
return is==it? EOF:*is++;
}
inline void put(char c){
obuf[cnt++]=c;
if(cnt==BUFSIZE) flush();
return;
}
struct AutoFlush{~AutoFlush(){flush();}}flusher;
inline int read(){
char c=get();int x=0,neg=0;
while(!isdigit(c)){
if(c=='-') neg^=1;
c=get();
}
do x=(x<<1)+(x<<3)+(c&15); while(isdigit(c=get()));
return neg? -x:x;
}
inline void c_write(const char*s,const char&c='\0'){
while(*s) put(*s++);
if(c) put(c);
}
inline void s_write(const string&s,const char&c='\0'){
for(char cc:s) put(cc);
if(c) put(c);
}
template<typename Tp>
inline void write(Tp x,const char& c='\0'){
if(x<0) put('-'),x=-x;
static int top=0,wr[50];
do wr[++top]=x%10; while(x/=10);
while(top) put(wr[top--]|48);
if(c) put(c);
return;
}
}
template<typename T>
struct Complex{
T rez,imz;
Complex(){rez=0.0,imz=0.0;}
Complex(lf x,lf y){rez=x,imz=y;}
Complex operator+(const Complex&b)const{return {rez+b.rez,imz+b.imz};}
Complex operator-(const Complex&b)const{return {rez-b.rez,imz-b.imz};}
Complex operator*(const Complex&b)const{return {rez*b.rez-imz*b.imz,rez*b.imz+imz*b.rez};}
void operator/=(const int&b){rez/=b,imz/=b;}
void operator*=(const Complex&b){*this=*this*b;}
Complex conj(){return {rez,-imz};}
};
template<typename T>
struct FFT{
const lf pi=3.141592653589793;
const lf pi2=6.283185307179586;
vector<Complex<T>>fft_a;
void init(int len){fft_a.resize(len);}
vector<int>rev;vector<Complex<lf>>omega;
void fft(int flag,int len){
for(int i=0;i<len;i++){
if(i<rev[i]) swap(fft_a[i],fft_a[rev[i]]);
}
for(int i=2;i<=len;i<<=1){
int t=len/i;
for(int j=0;j<len;j+=i){
for(int k=0;k<i/2;k++){
int idx=k*t;
if(flag<0) idx=len-idx;
if(idx>=len) idx-=len;
Complex<T>w=omega[idx];
Complex<T>x=fft_a[j+k];
Complex<T>y=w*fft_a[j+k+i/2];
fft_a[j+k]=x+y;
fft_a[j+k+i/2]=x-y;
}
}
}
if(flag==-1) for(int i=0;i<len;i++) fft_a[i]/=len;
}
void Init(int k){
rev.resize(1<<k,0);
int l=1<<k;
for(int i=0;i<l;i++) rev[i]=(rev[i>>1]>>1)|((i&1)<<(k-1));
omega.clear(),omega.resize(l);
omega[0]={1.0,0.0};
for(int i=1;i<l;i<<=1) omega[i]={cos(pi2*i/l),sin(pi2*i/l)};
for(int i=0;i<l;i++) omega[i]=omega[i&(-i)]*omega[i&(i-1)];
}
};
class UnsignedBigInt{
private:
static const int LEN=8,BASE=100000000,FFT_BASE=10000,T=255,INV=64;
static const ull MAX=ULLONG_MAX/(BASE+1),LOG=__lg(MAX)-1;
ull num[LENGTH];int len;
int Pow(int a,int p){
int res=1;
for(;p;p>>=1,a=a*a) if(p&1) res=res*a;
return res;
}
void Mul(const UnsignedBigInt&b){
ull* temp=new ull[len+b.len+5]();
for(int i=0;i<len;i++){
ull carry=0,t=num[i];
for(int j=0;j<b.len;j++){carry+=temp[i+j]+t*b.num[j];temp[i+j]=carry%BASE,carry/=BASE;}
temp[i+b.len]+=carry;
}
memset(num,0,sizeof(ull)*(len));len=len+b.len+5;
for(int i=0;i<len;i++) num[i]=temp[i];
for(int i=0;i<len;i++) num[i+1]+=num[i]/BASE,num[i]%=BASE;
while(len>1&&num[len-1]==0) len--;
delete[] temp;
}
ull Get(const UnsignedBigInt&a,int pos)const{
return 10ull*BASE*(pos+1>=a.len?0:a.num[pos+1])+10ull*a.num[pos]+(pos?a.num[pos-1]:0)/(BASE/10);
}
pair<UnsignedBigInt,UnsignedBigInt> Simple_Mod(const UnsignedBigInt&b)const{
if(b==0) Exit("Error:Division by zero!",Re_val);
if(*this<b) return make_pair(0,*this);
if(*this==b) return make_pair(1,0);
if(b.len<=2){ull q=b.num[0]+b.num[1]*BASE;return make_pair(*this/q,*this%q);}
UnsignedBigInt Q,R(*this);Q.len=len-b.len+1;
for(int i=len-b.len;i>=0;i--){
ull q=0;
auto Sub=[&](){
ll t=0;
for(int j=0;j<b.len;j++){
t=t-q*b.num[j]+R.num[i+j];
R.num[i+j]=(ull)(t%BASE),t/=BASE;
if(R.num[i+j]>=BASE) R.num[i+j]+=BASE,t--;
}
if(t) R.num[i+b.len]+=(ull)(t);
Q.num[i]+=q;
};
while((q=Get(R,i+b.len-1)/(Get(b,b.len-1)+1))) Sub();
q=1;
for(int j=b.len-1;j>=0;j--){if(R.num[j+i]!=b.num[j]&&(q=b.num[j]<R.num[i+j],true)) break;}
if(q) Sub();
}
while(Q.len>1&&Q.num[Q.len-1]==0) Q.len--;
while(R.len>1&&R.num[R.len-1]==0) R.len--;
return make_pair(Q,R);
}
UnsignedBigInt Left(int cnt)const{
if(cnt<0) Exit("Left Shift count is negative!",Re_val);
if(len+cnt>LENGTH) Exit("Left Shift:Memory Limit Exceeded",Re_val);
UnsignedBigInt res;
memmove(res.num+cnt,num,len*sizeof(ull)),memset(res.num,0,cnt*sizeof(ull));
res.len=len+cnt;return res;
}
UnsignedBigInt Right(int cnt)const{
if(cnt<0) Exit("Right Shift count is negative!",Re_val);
if(cnt>=len) return UnsignedBigInt();
UnsignedBigInt res;
memmove(res.num,num+cnt,(len-cnt)*sizeof(ull));
memset(res.num+(len-cnt),0,cnt*sizeof(ull));
res.len=len-cnt;
while(res.len>1&&res.num[res.len-1]==0) res.len--;
return res;
}
UnsignedBigInt Inv(int n)const{
if(*this==0) Exit("Error:Division by zero!",Re_val);
if(min(len,n-len)<=INV){
UnsignedBigInt a;a.len=n+1;a.num[n]=1;
return a.Simple_Mod(*this).first;
}
int k=(n-len+5)>>1,kk=k>len?0:len-k;
UnsignedBigInt t=Right(kk);
int n1=k+t.len;
UnsignedBigInt t1=t.Inv(n1);
UnsignedBigInt res=(t1+t1).Left(n-n1-kk)-(*this*t1*t1).Right(2*(n1+kk)-n);
return --res;
}
pair<UnsignedBigInt,UnsignedBigInt> Mod(const UnsignedBigInt&b)const{
if(*this<b) return make_pair(0,*this);
if(len<=T||b.len<=T) return Simple_Mod(b);
int Len=len-b.len+5,cnt=Len>b.len?0:b.len-Len;
UnsignedBigInt tem=b.Right(cnt);
if(cnt) tem++;
int inv=Len+tem.len;
UnsignedBigInt Q=(*this*tem.Inv(inv)).Right(inv+cnt);
while(Q*b>*this) Q--;
UnsignedBigInt R=*this-Q*b;
while(R>=b) Q++,R-=b;//here
return make_pair(Q,R);
}
public:
UnsignedBigInt(){
memset(num,0,sizeof num);
len=1;
}
UnsignedBigInt(const string&s){
if(s[0]=='-') Exit("QwQ,Cannot handle negative numbers.",Re_val);
for(int i=0;i<(int)s.size();i++){if(!isdigit(s[i])) Exit("Not a valid numeric string",Re_val);}
init();
int st=0;
len=(s.size()-st+LEN-1)/LEN;
if(len>=LENGTH) Exit(MLE,Re_val);
for(int i=s.size()-1,j=0;i>=st;i--,j++){
num[j/LEN]+=(s[i]-'0')*Pow(10,j%LEN);
}
while(len>1&&!num[len-1]) len--;
}
UnsignedBigInt(const UnsignedBigInt&b){
memset(num,0,sizeof num);
memcpy(num,b.num,b.len*sizeof(ull));
len=b.len;
}
UnsignedBigInt(const ull&b){
memset(num,0,sizeof num);len=0;
ull x=b;do{num[len]=x%BASE,len++;}while(x/=BASE);
while(len>1&&!num[len-1]) len--;
}
void init(){
memset(num,0,sizeof num);
len=1;
}
void fread(){
string s;
char c=IO::get();
while(!isgraph(c)) c=IO::get();
while(isgraph(c)&&c!=EOF) s+=c,c=IO::get();
*this=UnsignedBigInt(s);
}
void fwrite(const char&c='\0'){
IO::write(num[len-1]);
for(int i=len-2;i>=0;i--){
char buf[10];
sprintf(buf,"%08llu",num[i]);
IO::s_write(buf);
}
IO::put(c);
IO::flush();
}
int Two(){
if(num[0]%2){return 0;}
*this/=2;
return Two()+1;
}
int Cmp(const UnsignedBigInt&b){
if(len!=b.len) return len>b.len?1:-1;
for(int i=len-1;i>=0;i--){
if(num[i]!=b.num[i]) return num[i]>b.num[i]?1:-1;
}
return 0;
}
friend istream& operator>>(istream&in,UnsignedBigInt&x){
string s;in>>s;
if(in) x=UnsignedBigInt(s);
return in;
}
friend ostream& operator<<(ostream&out,const UnsignedBigInt&x){
out<<x.num[x.len-1];
for(int i=x.len-2;i>=0;i--){
char buf[10];
sprintf(buf,"%08llu",x.num[i]);
out<<buf;
}
return out;
}
bool operator<(const UnsignedBigInt&b)const{
if(len!=b.len) return len<b.len;
for(int i=len-1;i>=0;i--){
if(num[i]!=b.num[i]) return num[i]<b.num[i];
}
return 0;
}
bool operator>=(const UnsignedBigInt&b)const{return !((*this)<b);}
bool operator<=(const UnsignedBigInt&b)const{
if(len!=b.len) return len<b.len;
for(int i=len-1;i>=0;i--){
if(num[i]!=b.num[i]) return num[i]<b.num[i];
}
return 1;
}
bool operator>(const UnsignedBigInt&b)const{return !((*this)<=b);}
bool operator==(const UnsignedBigInt&b)const{
if(len!=b.len) return 0;
for(int i=0;i<len;i++){
if(num[i]!=b.num[i]) return 0;
}
return 1;
}
bool operator!=(const UnsignedBigInt&b)const{return !(*this==b);}
UnsignedBigInt& operator=(const UnsignedBigInt&b){
if(b.len>=LENGTH) Exit(MLE,Re_val);
if(this!=&b){memcpy(num,b.num,b.len*sizeof(ull)),len=b.len;}
return *this;
}
ull operator[](const int&b)const{return num[b];}
ull at(const int&b)const{if(b>=LENGTH) Exit("RE",Re_val);return num[b];}
UnsignedBigInt operator+(const UnsignedBigInt&b)const{
UnsignedBigInt c(*this);c+=b;
return c;
}
UnsignedBigInt operator+=(const UnsignedBigInt&b){
int n=max(len,b.len)+1;len=n;
for(int i=0;i<n;i++) num[i]+=b.num[i];
for(int i=0;i<n;i++){
if(num[i]>=BASE){
num[i+1]+=num[i]/BASE;num[i]%=BASE;
}
}
for(int i=n-1;i>=1;i--){
if(num[i]==0) len--;
else break;
}
return *this;
}
UnsignedBigInt operator++(){return *this+=1;}
UnsignedBigInt operator++(int){UnsignedBigInt res(*this);return *this+=1,res;}
UnsignedBigInt operator-(const UnsignedBigInt&b)const{
UnsignedBigInt c(*this);
c-=b;return c;
}
UnsignedBigInt operator-=(const UnsignedBigInt&b){
if(*this<b) Exit("QwQ,Cannot handle negative numbers.",Re_val);
ull t=0;
for(int i=0;i<len;i++){
ull sub=((i<b.len)?b.num[i]:0)+t;
if(num[i]<sub) num[i]=BASE+num[i]-sub,t=1;
else num[i]-=sub,t=0;
if(t==0&&i>=b.len) break;
}
while(len>1&&num[len-1]==0) len--;
return *this;
}
UnsignedBigInt operator--(){return *this-=1;}
UnsignedBigInt operator--(int){UnsignedBigInt res(*this);return *this-=1,res;}
UnsignedBigInt operator*(const UnsignedBigInt&b)const{
UnsignedBigInt c(*this);c*=b;
return c;
}
UnsignedBigInt operator*=(const UnsignedBigInt&b){
if(len<=T||b.len<=T){Mul(b);return *this;}
int k=1,Len=2,n=len,m=b.len;
while((1<<k)<n+m) k++,Len<<=1;
Len<<=1,k++;
FFT<lf>FFT_a,FFT_b;FFT_a.init(Len+1),FFT_b.init(Len+1);
for(int i=0;i<len;i++) FFT_a.fft_a[i<<1].rez=(lf)(num[i]%FFT_BASE),FFT_a.fft_a[i<<1|1].rez=(lf)(num[i]/FFT_BASE);
for(int i=0;i<b.len;i++) FFT_b.fft_a[i<<1].rez=(lf)(b.num[i]%FFT_BASE),FFT_b.fft_a[i<<1|1].rez=(lf)(b.num[i]/FFT_BASE);
if(Len>LENGTH) Exit(MLE,Re_val);
FFT_a.Init(k),FFT_b.Init(k);
FFT_a.fft(1,Len);
FFT_b.fft(1,Len);
for(int i=0;i<Len;i++) FFT_a.fft_a[i]*=FFT_b.fft_a[i];
FFT_a.fft(-1,Len);
memset(num,0,sizeof(int)*(Len));
for(int i=0;i<Len;i+=2){
int idx=i>>1;
__uint128_t t=(ull)(FFT_a.fft_a[i|1].rez+0.5)*FFT_BASE+(ull)(FFT_a.fft_a[i].rez+0.5);
num[idx]+=t%BASE;
num[idx+1]+=num[idx]/BASE;
num[idx]%=BASE;
num[idx+1]+=t/BASE;
}
len=(Len>>1)+1;
while(len>1&&!num[len-1]) len--;
return *this;
}
UnsignedBigInt operator/=(const UnsignedBigInt&b){*this=Mod(b).first;return *this;}
UnsignedBigInt operator/(const UnsignedBigInt&b)const{return Mod(b).first;}
UnsignedBigInt operator%=(const UnsignedBigInt&b){*this=Mod(b).second;return *this;}
UnsignedBigInt operator%(const UnsignedBigInt&b)const{return Mod(b).second;}
UnsignedBigInt operator*=(const ull&b){
if(b<=MAX){
len+=3;
for(int i=0;i<len;i++){num[i]*=b;}
for(int i=0;i<len;i++){num[i+1]+=num[i]/BASE,num[i]%=BASE;}
while(len>1&&!num[len-1]) len--;
}
else Mul(UnsignedBigInt(b));
return *this;
}
UnsignedBigInt operator*(const ull&b){
UnsignedBigInt c(*this);c*=b;
return c;
}
UnsignedBigInt operator/=(const ull&b){
if(b==0) Exit("Error:Division by zero!",Div_val);
__int128_t d=0;
for(int i=len-1;i>=0;i--){
d=d*BASE+num[i];num[i]=d/b;d%=b;
}
while(len>1&&!num[len-1]) len--;
return *this;
}
UnsignedBigInt operator/(const ull&b)const{
UnsignedBigInt c(*this);c/=b;
return c;
}
UnsignedBigInt operator%=(const ull&b){
if(b==0) Exit("Error:Division by zero!",Div_val);
__int128_t d=0;
for(int i=len-1;i>=0;i--){d=d*BASE+num[i];d%=b;}
return *this=d;
}
UnsignedBigInt operator%(const ull&b)const{UnsignedBigInt res(*this);res%=b;return res;}
UnsignedBigInt operator<<=(const ull&b){
UnsignedBigInt base("1");ull p=b;
for(;p;p>>=1,base*=2) if(p&1) *this*=base;
return *this;
}
UnsignedBigInt operator>>=(const ull&b){
ull x=b;
auto Div=[&](int cnt){
ull d=0;
for(int i=len-1;i>=0;i--){d=d*BASE+num[i];num[i]=(d>>cnt);d&=((1ull<<cnt)-1);}
while(len>1&&!num[len-1]) len--;
x-=cnt;
};
while(x>=LOG) Div(LOG);
Div(x);
return *this;
}
UnsignedBigInt operator>>(const ull&b)const{UnsignedBigInt res(*this);res>>=b;return res;}
UnsignedBigInt operator<<(const ull&b)const{UnsignedBigInt res(*this);res<<=b;return res;}
operator string()const{
string s="";
for(int i=len-1;i>=0;i--){char buf[10];sprintf(buf,"%08llu",num[i]);s+=buf;}
return s;
}
bool True()const{return !(len==1&&num[0]==0);}
UnsignedBigInt Pow(int p){
if(p==0) return UnsignedBigInt("1");
if(p==1) return *this;
UnsignedBigInt res("1"),t(*this);
for(;p;p>>=1){
if(p&1) res*=t;
if(p>1) t*=t;
}
return res;
}
UnsignedBigInt root(int m)const{
if(*this==0) return 0;
if(m==1) return *this;
UnsignedBigInt x(min(*this,UnsignedBigInt(BASE-1).Left((len+m-1)/m-1))),xx;
int top=x.len-1;
int l=0,r=BASE-1;
while(l<r){
int mid=(l+r)>>1;
x.num[top]=mid;
if(x.Pow(m)<=*this) l=mid+1;
else r=mid;
}
x.num[top]=l;
while(x.len>1&&!x.num[x.len-1]) x.len--;
xx=(x*(m-1)+*this/x.Pow(m-1))/m;
while(xx<x){
swap(x,xx);
xx=(x*(m-1)+*this/x.Pow(m-1))/m;
}
return x;
}
};
namespace Operation{
UnsignedBigInt Pow(const UnsignedBigInt&a,int p){
if(p==0) return UnsignedBigInt("1");
if(p==1) return a;
UnsignedBigInt res("1"),t(a);
for(;p;p>>=1){
if(p&1) res*=t;
if(p>1) t*=t;
}
return res;
}
UnsignedBigInt Fact(int st,int n){
if(n<=16){
UnsignedBigInt res=1;
for(int i=st;i<st+n;i++) res*=i;
return res;
}
int mid=(n+1)/2;
return Fact(st,mid)*Fact(st+mid,n-mid);
}
UnsignedBigInt Gcd(const UnsignedBigInt&a,const UnsignedBigInt&b){
UnsignedBigInt c(a),d(b);
int p=min(c.Two(),d.Two());
while(true){
int res=c.Cmp(d);
if(res>0) c-=d,c.Two();
else if(res<0) d-=c,d.Two();
else break;
}
c<<=p;
return c;
}
UnsignedBigInt Lcm(const UnsignedBigInt&a,const UnsignedBigInt&b){return a*b/Gcd(a,b);}
UnsignedBigInt Root(const UnsignedBigInt&a,ull p){return a.root(p);}
}
using namespace Operation;
#undef ll
#undef ull
#undef Exit
#undef MLE
#undef lf
#undef llf
#undef Re_val
#undef Div_val
#undef LENGTH
:::
对于各部分的解释欢迎评论。
后记
当然了,由于内存静态,在处理大数时往往略逊一筹;同时这也是本人的第一个项目,欢迎大家支持。
以后有时间会改为动态,应该是较久以后的事了。