zoukankan      html  css  js  c++  java
  • 二进制高精度模板(高精度)

    前言

    平时写高精度为什么要用十进制压位呢?主要是因为输入输出方便。

    但是十进制高精度数在运算时其实是偏慢的,因为过程中免不了要取模。

    取模运算是很慢的,可以试着让计算机进行(10^9)次乘法/取模,比一比两者的时间效率。

    还有就是,因为要防止乘法溢出,所以空间利用率低了。

    所以,下面的二进制高精度诞生了,不但兹瓷基本的算术运算,还兹瓷位运算。

    优势就在于,空间利用率大大提高了,每个二进制位都能被利用,比十进制高精度省一半的空间。

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

    唯一的不足就是输入输出太慢了,输入的时候每读入一个字符就要做一次错位加法。。。。。。输出的时候每次还要先取模。。。。。。

    所以,二进制高精度不适合用来计算过大的十进制整数运算(大致以(10^{1000})为界),也不适合需要频繁输入输出的题目。

    当运算次数较多、较复杂,而数的大小有一定限度的时候,是很好用的

    蒟蒻写这个就是为求烷烃同分异构体个数做准备。

    定长型

    如同long long只能在它的八个字节里进行操作一样,这种版本是一开始就规定好了长度的。

    用长度为(len)的unsigned long long数组压位(len是自定义的常量),能容纳数的大小是(2^{64len})(10^{64log2len}),约为(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({8over7}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='';
    			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;
    

    静态可变长型

    数组仍是定长,但是记录了最高位,减少冗余的空计算,适合数不大而不稳定的计算。

    感觉要咕咕了

    动态可变长型

    感觉要咕咕了

  • 相关阅读:
    POJ 1401 Factorial
    POJ 2407 Relatives(欧拉函数)
    POJ 1730 Perfect Pth Powers(唯一分解定理)
    POJ 2262 Goldbach's Conjecture(Eratosthenes筛法)
    POJ 2551 Ones
    POJ 1163 The Triangle
    POJ 3356 AGTC
    POJ 2192 Zipper
    POJ 1080 Human Gene Functions
    POJ 1159 Palindrome(最长公共子序列)
  • 原文地址:https://www.cnblogs.com/flashhu/p/9123906.html
Copyright © 2011-2022 走看看