• 二进制高精度模板(高精度)


    前言

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

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

    取模运算是很慢的,可以试着让计算机进行(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;
    

    静态可变长型

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

    感觉要咕咕了

    动态可变长型

    感觉要咕咕了

  • 相关阅读:
    SQL 中文排序方式
    ASP.NET公有六种验证控件
    CustomValidator的使用方法
    c# 获取网页源码
    asp.net mvc 从客户端中检测到有潜在危险的 Request.Form 值的解决方法
    C#上传文件转字节流形式
    byte数组转换成文件保存到本地
    检测到有潜在危险的Request.Form值
    字节数组生成图片
    Edit Distance (编辑距离) .NET 实现
  • 原文地址:https://www.cnblogs.com/flashhu/p/9123906.html
Copyright © 2020-2023  润新知