二進制高精度模板(高精度)


前言

平時寫高精度為什么要用十進制壓位呢?主要是因為輸入輸出方便。

但是十進制高精度數在運算時其實是偏慢的,因為過程中免不了要取模。

取模運算是很慢的,可以試着讓計算機進行\(10^9\)次乘法/取模,比一比兩者的時間效率。

還有就是,因為要防止乘法溢出,所以空間利用率低了。

所以,下面的二進制高精度誕生了,不但茲瓷基本的算術運算,還茲瓷位運算。

優勢就在於,空間利用率大大提高了,每個二進制位都能被利用,比十進制高精度省一半的空間。

第二就是運算速度提高了,很多運算快了數倍,尤其乘除模的效率可達10倍以上。

唯一的不足就是輸入輸出太慢了,輸入的時候每讀入一個字符就要做一次錯位加法。。。。。。輸出的時候每次還要先取模。。。。。。

所以,二進制高精度不適合用來計算過大的十進制整數運算(大致以\(10^{1000}\)為界),也不適合需要頻繁輸入輸出的題目。

當運算次數較多、較復雜,而數的大小有一定限度的時候,是很好用的

蒟蒻寫這個就是為求烷烴同分異構體個數做准備。

定長型

如同long long只能在它的八個字節里進行操作一樣,這種版本是一開始就規定好了長度的。

用長度為\(len\)的unsigned long long數組壓位(len是自定義的常量),能容納數的大小是\(2^{64len}\)\(10^{64\log2len}\),約為\(10^{19len}\)

大致分析一下復雜度

位運算,邏輯運算,加減是線性\(O(len)\)的;

乘法進行了小小的優化,把unsigned long long拆分成兩個unsigned int再進行錯位相乘求和,比用位移錯位相加快幾十倍,復雜度\(O(2len^2)\)

高精度除法和取模沒辦法優化,只能位移錯位相減,復雜度\(O(64len^2)\)

為了在一定程度上彌補這樣的不足,蒟蒻由重載了高精除/模低精,復雜度取決於低精度數\(n\)的大小,如果它實際占用了\(d\)個字節(從最高非0位算起)(形式化地,\(d=log_{256}n\)),則復雜度為\(O({{7len}\over{7-d}})\)。當然如果有一個\(d=8\)的long long也只好變成高精。

讀入和快讀很像,讀一個字符就要乘\(10\),當然這里寫(x<<3)+(x<<1)快,復雜度\(O(2len|S|)\)

輸出和快寫很像,加了個指針優化,防止內存頻繁移動,復雜度\(O({8\over7}len|S|)\)

這一個是無符號型,因此除了負號運算符-,所有的整數運算符都完成了重載。

其實有符號型只要把最高位當成符號位,就可以直接利用補碼進行運算啦!改動很小,就不詳細展開了。

唯一與普通整數使用的差別感是在與bool型的轉化上。整數可以直接轉化成bool,而bool是系統自帶類型,不能重載高精度數的強制轉化,所以把\(x\)轉成bool要寫!!x

#include<cassert>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<string>
using namespace std;
namespace hjt{
#define RG register
#define UI unsigned int
#define UL unsigned long long
#define FR(op,re) inline friend re operator op(RG bign a,RG bign b)
#define OP(op,re,tp) inline re operator op(RG tp a)
#define ON(op,re) inline re operator op()
#define EQ(op,tp) OP(op,bign&,tp)
#define clear memset(n,0,SIZE)
#define bitop(op,eq)							\
	FR(op,bign){								\
		for(RG UI i=0;i<LEN;++i)				\
			a.n[i]eq b.n[i];					\
		return a;								\
	}											\
	EQ(eq,bign){								\
		for(RG UI i=0;i<LEN;++i)				\
			n[i]eq a.n[i];						\
		return*this;							\
	}
#define logop(op,re) FR(op,bool){				\
		for(RG UI i=LEN-1;i;--i)				\
			if(a.n[i]!=b.n[i])return re;		\
		return a.n[0]op b.n[0];					\
	}
	
	const int LEN=10000,SIZE=LEN<<3;//LEN is decided by yourself
	
	struct bign{
		UL n[LEN];
		
		//initializations
		EQ(=,UL){clear;n[0]=a;return*this;}
		EQ(=,const char*){
			clear;
			while(isdigit(*a))
				*this=(*this<<3)+(*this<<1)+(*a++&15);
			return*this;
		}
		template<typename TP>
		inline bign(RG TP a){*this=a;}
		inline bign(){clear;}
		
		//bit operations
		ON(~,bign){
			RG bign ret;
			for(RG UI i=0;i<LEN;++i)
				ret.n[i]=~n[i];
			return ret;
		}
		OP(<<,bign,UI){
			RG bign ret;
			if(a>=SIZE<<3)return ret;
			RG UI i,d=a>>6,l=a&63;
			if(l){
				RG UI r=64-l;
				for(i=LEN-d-1;i;--i)
					ret.n[i+d]=n[i]<<l|n[i-1]>>r;
				ret.n[d]=n[0]<<l;
				return ret;
			}
			for(i=LEN-d-1;~i;--i)ret.n[i+d]=n[i];
			return ret;
		}
		EQ(<<=,UI){
			if(a>=SIZE<<3){clear;return*this;}
			RG UI i,d=a>>6,l=a&63;
			if(l){
				RG UI r=64-l;
				for(i=LEN-d-1;i;--i)
					n[i+d]=n[i]<<l|n[i-1]>>r;
				n[d]=n[0]<<l;
			}
			else for(i=LEN-d-1;~i;--i)n[i+d]=n[i];
			for(i=d-1;~i;--i)n[i]=0;
			return*this;
		}
		OP(>>,bign,UI){
			RG bign ret;
			if(a>=SIZE<<3)return ret;
			RG UI i,d=a>>6,r=a&63;
			if(r){
				RG UI l=64-r;
				for(i=d;i<LEN-1;++i)
					ret.n[i-d]=n[i]>>r|n[i+1]<<l;
				ret.n[i-d]=n[i]>>r;
				return ret;
			}
			for(i=d;i<LEN;++i)ret.n[i-d]=n[i];
			return ret;
		}
		EQ(>>=,UI){
			if(a>=SIZE<<3){clear;return*this;}
			RG UI i,d=a>>6,r=a&63;
			if(r){
				RG UI l=64-r;
				for(i=d;i<LEN-1;++i)
					n[i-d]=n[i]>>r|n[i+1]<<l;
				n[i-d]=n[i]>>r;
			}
			else for(i=d;i<LEN;++i)n[i-d]=n[i];
			for(i=LEN-d;i<LEN;++i)n[i]=0;
			return*this;
		}
		bitop(&,&=);
		bitop(^,^=);
		bitop(|,|=);
		
		//logic operations
		logop(<,a.n[i]<b.n[i]);
		logop(>,a.n[i]>b.n[i]);
		logop(<=,a.n[i]<b.n[i]);
		logop(>=,a.n[i]>b.n[i]);
		logop(==,0);
		logop(!=,1);
		ON(!,bool){
			for(RG UI i=0;i<LEN;++i)
				if(n[i])return 0;
			return 1;
		}
		FR(&&,bool){return !!a&&!!b;}
		FR(||,bool){return !!a||!!b;}
		
		//arithmetic operation
		ON(++,bign&){for(RG UI i=0;!++n[i]&&i<LEN;++i);return*this;}
		ON(--,bign&){for(RG UI i=0;!n[i]--&&i<LEN;++i);return*this;}
		FR(+,bign){
			RG bool car=0;
			for(RG UI i=0;i<LEN;++i){
				a.n[i]+=b.n[i]+car;
				car=car?a.n[i]<=b.n[i]:a.n[i]<b.n[i];
			}
			return a;
		}
		EQ(+=,bign){
			RG bool car=0;
			for(RG UI i=0;i<LEN;++i){
				n[i]+=a.n[i]+car;
				car=car?n[i]<=a.n[i]:n[i]<a.n[i];
			}
			return*this;
		}
		FR(-,bign){
			RG bool bor=0;RG UL lst;
			for(RG UI i=0;i<LEN;++i){
				lst=a.n[i];a.n[i]-=b.n[i]+bor;
				bor=bor?lst<=a.n[i]:lst<a.n[i];
			}
			return a;
		}
		EQ(-=,bign){
			RG bool bor=0;RG UL lst;
			for(RG UI i=0;i<LEN;++i){
				lst=n[i];n[i]-=a.n[i]+bor;
				bor=bor?lst<=n[i]:lst<n[i];
			}
			return*this;
		}
		FR(*,bign){
			RG bign ret;
			RG UI*p=(UI*)&a,*q=(UI*)&b,i,j,k;
			RG UL*r=ret.n,mul;
			for(i=(LEN-1)<<1,k=0;k<i;++k,r=(UL*)((UI*)r+1))
				for(j=k;~j;--j){
					mul=(UL)p[j]*q[k-j];
					if((*r+=mul)<mul)++*(r+1);
				}
			for(j=k;~j;--j)
				*r+=(UL)p[j]*q[k-j];
			for(j=++k;~j;--j)
				*(UI*)(r+1)+=p[j]*q[k-j];
			return ret;
		}
		EQ(*=,bign){
			RG bign b=*this;
			RG UI*p=(UI*)&a,*q=(UI*)&b,i,j,k;
			RG UL*r=n,mul;
			clear;
			for(i=(LEN-1)<<1,k=0;k<i;++k,r=(UL*)((UI*)r+1))
				for(j=k;~j;--j){
					mul=(UL)p[j]*q[k-j];
					if((*r+=mul)<mul)++*(r+1);
				}
			for(j=k;~j;--j)
				*r+=(UL)p[j]*q[k-j];
			for(j=++k;~j;--j)
				*(UI*)(r+1)+=p[j]*q[k-j];
			return*this;
		}
		FR(/,bign){
			assert(!!b);
			if(a<b)return 0;
			RG bign cur,ret;RG UI i,j,e;RG UL t;
			for(i=LEN-1;!a.n[i];--i);
			for(j=i<<6,t=a.n[i]>>1;t;++j,t>>=1);
			for(i=LEN-1;!b.n[i];--i);
			for(e=i<<6,t=b.n[i]>>1;t;++e,t>>=1);
			for(j-=e;~j;--j)
				if(a>=(cur=b<<j))
					ret.n[j>>6]|=1ull<<j,a-=cur;
			return ret;
		}
		EQ(/=,bign){
			assert(!!a);
			if(*this<a){clear;return*this;}
			RG bign b=*this,cur;RG UI i,j,e;RG UL t;
			for(i=LEN-1;!n[i];--i);
			for(j=i<<6,t=n[i]>>1;t;++j,t>>=1);
			for(i=LEN-1;!a.n[i];--i);
			for(e=i<<6,t=a.n[i]>>1;t;++e,t>>=1);
			clear;
			for(j-=e;~j;--j)
				if(b>=(cur=a<<j))
					n[j>>6]|=1ull<<j,b-=cur;
            return*this;
		}
		FR(%,bign){
			assert(!!b);
			if(a<b)return a;
			RG bign cur;RG UI i,j,e;RG UL t;
			for(i=LEN-1;!a.n[i];--i);
			for(j=i<<6,t=a.n[i]>>1;t;++j,t>>=1);
			for(i=LEN-1;!b.n[i];--i);
			for(e=i<<6,t=b.n[i]>>1;t;++e,t>>=1);
			for(j-=e;~j;--j)
				if(a>=(cur=b<<j))a-=cur;
			return a;
		}
		EQ(%=,bign){
			assert(!!a);
			if(*this<a)return*this;
			RG bign cur;RG UI i,j,e;RG UL t;
			for(i=LEN-1;!a.n[i];--i);
			for(e=i<<6,t=a.n[i]>>1;t;++e,t>>=1);
			for(i=LEN-1;!n[i];--i);
			for(j=i<<6,t=n[i]>>1;t;++j,t>>=1);
			for(j-=e;~j;--j)
				if(*this>=(cur=a<<j))*this-=cur;
			return*this;
		}
		OP(/,bign,UL){
			assert(a);
			RG char*p=(char*)&a;RG UI d;
			for(d=7;!p[d];--d);
			if(!(d=7-d))return*this/(bign)a;
			RG bign b=*this,ret;RG UL*cur;
			RG char*r=(char*)&ret;p=(char*)&b;
			for(RG int i=SIZE-8;i>0;i-=d)
				*(UL*)(r+i)|=*(cur=(UL*)(p+i))/a,*cur%=a;
			*(UL*)r|=*(UL*)p/a;
			return ret;
		}
		OP(/=,bign&,UL){
			assert(a);
			RG char*p=(char*)&a;RG UI d;
			for(d=7;!p[d];--d);
			if(!(d=7-d))return*this/=(bign)a;
			RG bign b=*this;RG UL*cur;
			RG char*r=(char*)this;p=(char*)&b;
			clear;
			for(RG int i=SIZE-8;i>0;i-=d)
				*(UL*)(r+i)|=*(cur=(UL*)(p+i))/a,*cur%=a;
			*(UL*)r|=*(UL*)p/a;
			return *this;
		}
		OP(%,bign,UL){
			assert(a);
			RG char*p=(char*)&a;RG UI d;
			for(d=7;!p[d];--d);
			if(!(d=7-d))return*this%(bign)a;
			RG bign ret=*this;p=(char*)&ret;
			for(RG int i=SIZE-8;i>0;i-=d)
				*(UL*)(p+i)%=a;
			*(UL*)p%=a;
			return ret;
		}
		OP(%=,bign&,UL){
			assert(a);
			RG char*p=(char*)&a;RG UI d;
			for(d=7;!p[d];--d);
			if(!(d=7-d))return*this%=(bign)a;
			p=(char*)this;
			for(RG int i=SIZE-8;i>0;i-=d)
				*(UL*)(p+i)%=a;
			*(UL*)p%=a;
			return*this;
		}
		friend inline istream&operator>>(RG istream&in,RG bign&a){
			RG string s;
			in>>s;a=s.c_str();
			return in;
		}
		friend inline ostream&operator<<(RG ostream&ou,RG bign a){
			RG char s[LEN*20],*p=s+LEN*20-1;*p='\0';
			RG bign b;RG int i,j;RG UL*cur;
			RG char*q=(char*)&a,*r=(char*)&b,*t;
			for(i=SIZE-1;!q[i];--i);
			while(i>7){
				for(j=i-7;j>0;j-=7)
					*(UL*)(r+j)|=*(cur=(UL*)(q+j))/10,*cur%=10;
				*(UL*)r|=*(cur=(UL*)q)/10;*--p=*cur%10+'0';*cur=0;
				t=q;q=r;r=t;
				while(!q[i])--i;
			}
			return ou<<*(UL*)q<<p;
		}
	};
#undef RG
#undef UI
#undef UL
#undef FR
#undef OP
#undef ON
#undef EQ
#undef clear
#undef bitop
#undef bitopeq
#undef logop
}
using namespace hjt;

靜態可變長型

數組仍是定長,但是記錄了最高位,減少冗余的空計算,適合數不大而不穩定的計算。

感覺要咕咕了

動態可變長型

感覺要咕咕了


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM