高精度整数模板(转)
来源:互联网 发布:x77大陆永久域名 编辑:程序博客网 时间:2024/06/06 08:33
- * *
- * 高精度模板 *
- * *
- * 功能:超长符号整数(HarInt)+,-,*,/,%,+=,-=,*=,/=,%= 等运算 *
- *支持大小比较<,>,==,!=,<=,>=*
- * 多种操作运算符的重载 *
- *说明:HarInt采用一个有上界的数组及一个bool变量表示 *
- * 数组的第一位表示数的位数,bool变量表示数的符号 *
- * 特殊数字0的符号强制为正,即bool值为true*
- * 采用了9位整形数为计算单元,提高运算效率 *
- * 加法,减法,乘法采用了比较简单的模拟运算,效率一般*
- * 除法采用了二分试商,取最高二位取商的最大值及最小值,然后二分试商*
- * *
- *************************** All RightsReserved ********************************/
- #include<iostream>
- #define MAXLEN450//数组长度上限,可以根据需求自行设置
- #define BASE_DIGIT9//运算的进制,9代表以10^9计算
- #define BASE1000000000//10^9进制
- #define PRINTCHAR ("d")//专长整数输出定义的字符串
- #define IsDigit(c)(('0'<=(c))&&((c)<='9'))//判断字符c是否为数字
- using namespace std;
- charinstr[MAXLEN*BASE_DIGIT+1];
- shortCMP(const int *a,const int*b){//比较数组大整数,也就是大整数的绝对值
- if(a[0]<b[0])//数位少的小
- return -1;
- if(a[0]>b[0])//数位多的大
- return 1;
- for(inti=a[0];i>0;i--)
- {
- if(a[i]<b[i])//高位小的小
- return -1;
- if(a[i]>b[i])//高位大的数大
- return 1;
- }
- return 0;
- }
- void ADD(const int*a,const int *b,int *c){//数组表示的大整数加法
- memset(c,0,sizeof(int)*MAXLEN);
- intla=a[0],lb=b[0],d=0;
- c[0]=(la>lb?la:lb)+1;
- for(inti=1;i<=c[0];i++)
- {
- c[i]= a[i]+b[i]+d;
- d=0;
- if(c[i]>=BASE)
- {//需要进位
- d=1;
- c[i]-=BASE;
- }
- }
- while(c[0]>1&&c[c[0]]==0)//消去前导零
- c[0]--;
- }
- voidSUB(const int *a,const int*b,int*c){//减法
- memset(c,0,sizeof(int)*MAXLEN);
- c[0]=a[0];
- int d=0;
- for(inti=1;i<=a[0];i++)
- {
- c[i]=a[i]-b[i]-d;
- d=0;
- if(c[i]<0)
- {//需要借位
- c[i]+=BASE;
- d++;
- }
- }
- while(c[0]>1&&c[c[0]]==0)
- c[0]--;//消去前导零
- return;
- }
- voidMUL(const int *a,const int*b,int*c){//乘法
- memset(c,0,sizeof(int)*MAXLEN);
- __int64t=0;
- int l =a[0]+b[0]+1;
- c[0]=l;
- for(inti=1;i<=a[0];i++)
- for(intj=1;j<=b[0];j++)
- {
- t=(__int64)c[i+j-1]+(__int64)a[i]*(__int64)b[j];
- c[i+j-1]=t�SE;
- c[i+j] += t/BASE;//存储进位
- }
- while(c[0]>1&&c[c[0]]==0)
- c[0]--;//消去前导零
- }
- voidMUL(const int *a,int b,int *c){//高精乘单精
- memset(c,0,sizeof(int)*MAXLEN);
- int l = a[0] +1 ;
- __int64 t=0;
- for(inti=1;i<=l;i++)
- {
- t = (__int64)a[i]*b + (__int64)c[i];
- c[i+1] = t/BASE;
- c[i] = (t�SE);
- }
- while(c[l]==0&&l>1)l--;
- c[0]=l;
- }
- void DIV(const int*a,const int *b,int *c,int *d){//除法
- memset(c,0,sizeof(int)*MAXLEN);memset(d,0,sizeof(int)*MAXLEN);
- int *t1 =new int[MAXLEN],*t2 = new int[MAXLEN];
- intla=a[0],lb=b[0],ld=0,min=0,max=0,mid=0,l = la;
- doubletdmin=0,tdmax=0,tbmin=b[lb],tbmax=tbmin+1.0;
- if(lb>1)
- {//取两个高位的值,用作试商
- tbmin = tbmin*(double)BASE + (double)b[lb-1];
- tbmax = tbmin+1.0;
- }
- for(inti=l;i>0;i--)
- {
- for(intj=d[0];j>=1;j--)d[j+1]=d[j];d[1]=a[i];
- if(d[d[0]+1]!=0)d[0]++;
- if(CMP(d,b)<0)
- continue;
- ld = d[0];
- tdmin = d[ld];
- int j = 1;
- while(tdmin<tbmin)
- {
- tdmin = tdmin*BASE + d[ld-j];
- j++;
- }
- tdmax = tdmin+1.0;
- max =(int)(tdmax/tbmin)+1;min=(int)(tdmin/tbmax)-1;
- while(true)
- {//二分试商
- mid = (min+max)/2;
- MUL(b,mid,t1);
- if(CMP(d,t1)<0){max =mid-1;continue;}//试商偏高,改变max值
- SUB(d,t1,t2);
- if(CMP(t2,b)>=0){min =mid+1;continue;}//试商偏低,改变min值
- break;//试商成功,此mid值为该位的商值
- }
- c[i]=mid;
- memcpy(d,t2,sizeof(int)*MAXLEN);//t2为余值,赋给d
- }
- delete[]t1;delete[]t2;
- while(c[l]==0&&l>1)l--;
- c[0]=l;//消去前导零
- }
- class HarInt{
- private:
- intnumb[MAXLEN];//具体数字,第0位表示数字长度,第一位及以后分别表示数字的高位至低位
- boolflag;
- public:
- HarInt(){}
- ~HarInt(){}
- boolParse(const char *s){
- clear();intl=strlen(s),i=0,nl=1;flag = true;//默认为非负数
- if(s[0]=='-'){i++;flag = false;}//为负数,数值从第2位开始
- for(intj=l-1;j>=i;j-=BASE_DIGIT)
- {//从高位至低位一位一位转
- int n=0,ten=1;
- for(intk=0;(k<BASE_DIGIT&&j-k>=i);k++)
- {
- if(!IsDigit(s[j-k])){clear();returnfalse;}//含非数字字符,赋值失败
- n+=(s[j-k]-'0')*ten;ten*=10;
- }
- numb[nl++]=n;//从第一位开始给数组numb赋值,第0位预留为数字长
- }
- nl--;while(numb[nl]==0&&nl>1)nl--;//消去前导零
- numb[0]=nl;return true;//赋值成功
- }
- voidclear(){memset(numb,0,sizeof(int)*MAXLEN);}
- voidParse(const HarInthi){
- memcpy(numb,hi.numb,sizeof(int)*MAXLEN);
- flag = hi.flag;
- }
- voidvalue(const int a){
- intt=a;
- flag=true;if(t<0){flag=false;t*=-1;}
- numb[0]=1;numb[1]=t;
- }
- intoperator[](inti){returnnumb[i];}
- boolFlag(){returnflag;}
- boolisZero(){return(numb[0]==1&&numb[1]==0);}
- intGet(){if(scanf("%s",instr)==EOF)return EOF;return Parse(instr);}
- voidprint(chars){
- if(!flag)putchar('-');
- printf("%d",numb[numb[0]]);
- for(inti=numb[0]-1;i>=1;i--)
- printf(PRINTCHAR,numb[i]);
- putchar(s);
- }
- friend shortHarIntCmp(HarInt,HarInt);//友元比较函数
- friend voidDIV(HarInt,HarInt,HarInt&,HarInt&);//友元除法函数
- HarInt& operator+=(const HarInt&a){//重载+=运算符,实现大整数的+=运算
- int *n= new int[MAXLEN];
- memcpy(n,numb,sizeof(int)*MAXLEN);
- if(flag==a.flag)//同号,绝对值直接相加,符号不变
- ADD(n,a.numb,numb);
- else{//异号则绝对值大的减绝对值小的,符号与绝对值大的相同
- int c =CMP(n,a.numb);//比较两数的绝对值
- if(c==0){numb[0]=1;numb[1]=0;flag=true;}//|a|==|b|&&a*b<0则a-b=0;
- else if(c<0){SUB(a.numb,n,numb);flag=a.flag;}//|a|<|b|
- elseSUB(n,a.numb,numb);
- }
- delete[]n;n=NULL;
- return *this;
- }
- HarInt& operator-=(const HarInt&a){//重载-=运算符,实现大整数的-=运算
- int *n= new int[MAXLEN];
- memcpy(n,numb,sizeof(int)*MAXLEN);
- if(flag!=a.flag)//异号,绝对值直接相加,符号不变
- ADD(n,a.numb,numb);
- else{//同号,绝对值大减小,符号由两数的大小确定
- int c =CMP(n,a.numb);
- if(c==0){numb[0]=1;numb[1]=0;flag=true;}//0
- else if(c<0){SUB(a.numb,n,numb);flag=!flag;}//a<b符号取反
- elseSUB(n,a.numb,numb);//a>b符号不变
- }
- delete[]n;n=NULL;
- return *this;
- }
- HarInt& operator*=(const HarInt&a){//重载*=运算符,实现大整数的*=运算
- int *n= new int[MAXLEN];
- memcpy(n,numb,sizeof(int)*MAXLEN);
- MUL(n,a.numb,numb);//绝对值相乘
- flag = (flag==a.flag);//同号取正,异号取负
- delete[]n;n=NULL;
- return *this;
- }
- HarInt& operator/=(const HarInt&a){//重载/=运算符,实现大整数的/=运算
- int *n1= new int[MAXLEN],*n2 = new int[MAXLEN];
- memcpy(n1,numb,sizeof(int)*MAXLEN);
- DIV(n1,a.numb,numb,n2);//绝对值相除
- delete[]n1;delete[]n2;
- flag = (flag==a.flag);//同号取正,异号取负
- return *this;
- }
- HarInt& operator%=(const HarInt&a){//重载%=运算符,实现大整数的%=运算
- int *n1= new int[MAXLEN],*n2 = new int[MAXLEN];
- memcpy(n1,numb,sizeof(int)*MAXLEN);
- DIV(n1,a.numb,n2,numb);
- delete[]n1;delete[]n2;
- flag = (flag==a.flag);
- return *this;
- }
- };
- void DIV(HarInta,HarInt b,HarInt& c,HarInt&d){//除法,一次运算同时取得商与余数
- c.flag= (a.flag==b.flag);d.flag=c.flag;
- DIV(a.numb,b.numb,c.numb,d.numb);
- return ;
- }
- short HarIntCmp(HarInta,HarInt b){
- if(a.Flag()>b.Flag())//正数恒大于负数
- return 1;
- if(a.Flag()<b.Flag())//负数恒小于正数
- return -1;
- if(a[0]<b[0])//数位少的数值小,根据符号判断大小
- return((!a.Flag())?1:-1);
- if(a[0]>b[0])
- return(a.Flag()?1:-1);
- for(inti=a[0];i>=1;i--)
- {
- if(a[i]<b[i])
- return((!a.Flag())?1:-1);
- if(a[i]>b[i])
- return(a.Flag()?1:-1);
- }
- return 0;
- }
- booloperator<(HarInt a,HarIntb){return(HarIntCmp(a,b)<0);}
- booloperator>(HarInt a,HarIntb){return(HarIntCmp(a,b)>0);}
- booloperator==(HarInt a,HarInt b){return (HarIntCmp(a,b)==0);}
- bool operator!=(HarInta,HarInt b){return(HarIntCmp(a,b)!=0);}
- booloperator<=(HarInt a,HarIntb){return(HarIntCmp(a,b)<=0);}
- booloperator>=(HarInt a,HarIntb){return(HarIntCmp(a,b)>=0);}
- HarInt operator+(const HarInt&a,constHarInt& b){HarIntc=a;c+=b;returnc;}
- HarInt operator+(const HarInt&a,const int b){HarIntc;c.value(b);c+=a;returnc;}
- HarInt operator-(const HarInt&a,constHarInt& b){HarIntc=a;c-=b;returnc;}
- HarInt operator-(const HarInt&a,const int b){HarIntc;c.value(b);return(a-c);}
- HarInt operator*(const HarInt&a,constHarInt& b){HarIntc=a;c*=b;returnc;}
- HarInt operator*(const HarInt&a,const int b){HarIntc;c.value(b);c*=a;returnc;}
- HarInt operator/(const HarInt&a,constHarInt& b){HarIntc=a;c/=b;returnc;}
- HarInt operator/(const HarInt&a,const int b){HarIntc;c.value(b);return(a/c);}
- HarInt operator%(const HarInt&a,constHarInt& b){HarIntc=a;c%=b;returnc;}
- HarInt operator%(const HarInt&a,const int b){HarIntc;c.value(b);return(a%c);}