关于C++高精度运算的几种方式 今天刚好写到了一题需要高精的题,查题解时看到了 __int64 ,想来想去就决定复习一下高精度运算了~~~
传统数组模拟加减乘除法运算( noip 常见算法) 传统数组高精,实际上就是模拟人类在草稿纸上笔算的过程。(如果你是数学大佬,那我告辞)
高精度加法 直接附代码了(下面都是)
#include  <iostream>   #include  <cstdio>  #include  <cstring>  using  namespace  std ;int  main () 	char  a1[600 ],b1[600 ]; 	int  a[600 ],b[600 ],c[600 ],lena,lenb,lenc,i,x; 	memset (a,0 ,sizeof (a)); 	memset (b,0 ,sizeof (b)); 	memset (c,0 ,sizeof (c)); 	cin >>a1>>b1; 	lena=strlen (a1); 	lenb=strlen (b1); 	for (i=0 ;i<=lena-1 ;i++) 		a[lena-i]=a1[i]-48 ; 	for (i=0 ;i<=lenb-1 ;i++) 		b[lenb-i]=b1[i]-48 ; 	lenc=1 ; 	x=0 ; 	while (lenc<=lena||lenc<=lenb) 	{ 		c[lenc]=a[lenc]+b[lenc]+x; 		x=c[lenc]/10 ; 		c[lenc]%=10 ; 		lenc++; 	} 	c[lenc]=x; 	if (c[lenc]==0 ) 		lenc--; 	for (i=lenc;i>=1 ;i--) 		cout <<c[i]; 	cout <<endl ; 	return  0 ; } 
高精度减法 #include  <iostream>   #include  <cstdio>  #include  <cstring>  using  namespace  std ;int  main () 	char  n[100 ],a1[100 ],b1[100 ]; 	int  a[100 ],b[100 ],c[100 ],lena,lenb,lenc,i,x; 	memset (a,0 ,sizeof (a)); 	memset (b,0 ,sizeof (b)); 	memset (c,0 ,sizeof (c)); 	gets(a1); 	gets(b1); 	if (strlen (a1)<strlen (b1)||(strlen (a1)==strlen (b1)&&strcmp (a1,b1)<0 )) 	{ 		strcpy (n,a1); 		strcpy (a1,b1); 		strcpy (b1,n); 		cout <<"-" ; 	} 	lena=strlen (a1); 	lenb=strlen (b1); 	for (i=0 ;i<=lena-1 ;i++) 		a[lena-i]=a1[i]-48 ; 	for (i=0 ;i<=lenb-1 ;i++) 		b[lenb-i]=b1[i]-48 ; 	lenc=1 ; 	while (lenc<=lena||lenc<=lenb) 	{ 		if (a[lenc]<b[lenc]) 		{ 			a[lenc]+=10 ; 			a[lenc+1 ]--; 		} 		c[lenc]=a[lenc]-b[lenc]; 		lenc++; 	} 	while ((c[lenc]==0 )&&(lenc>1 )) 		lenc--; 	for (i=lenc;i>=1 ;i--) 		cout <<c[i]; 	cout <<endl ; 	return  0 ;  } 
高精度乘法 #include  <iostream>  #include  <cstring>  #include  <cstdio>  using  namespace  std ;int  main () 	char  a1[2002 ],b1[2002 ]; 	int  a[2002 ],b[2002 ],c[4002 ],lena,lenb,lenc,i,j,x; 	memset (a,0 ,sizeof (a)); 	memset (b,0 ,sizeof (b)); 	memset (c,0 ,sizeof (c)); 	cin >>a1>>b1; 	lena=strlen (a1); 	lenb=strlen (b1); 	for (i=0 ;i<=lena-1 ;i++) 		a[lena-i]=a1[i]-48 ; 	for (i=0 ;i<=lenb-1 ;i++) 		b[lenb-i]=b1[i]-48 ; 	for (i=1 ;i<=lena;i++) 	{ 		x=0 ; 		for (j=1 ;j<=lenb;j++) 		{ 			c[i+j-1 ]=a[i]*b[j]+x+c[i+j-1 ]; 			x=c[i+j-1 ]/10 ; 			c[i+j-1 ]%=10 ; 		} 		c[i+lenb]=x; 	} 	lenc=lena+lenb; 	while (c[lenc]==0 &&lenc>1 ) 		lenc--; 	for (i=lenc;i>=1 ;i--) 		cout <<c[i]; 	cout <<endl ; 	return  0 ; }  
高精度除法 高精除低精 #include  <iostream>  #include  <cstring>  #include  <cstdio>  using  namespace  std ;int  main () 	char  a1[100 ],c1[100 ]; 	int  a[100 ],c[100 ],lena,i,x=0 ,lenc,b; 	memset (a,0 ,sizeof (a)); 	memset (c,0 ,sizeof (c)); 	gets(a1); 	cin >>b; 	lena=strlen (a1); 	for (i=0 ;i<=lena-1 ;i++) 		a[i+1 ]=a1[i]-48 ; 	for (i=0 ;i<=lena;i++) 	{ 		c[i]=(x*10 +a[i])/b; 		x=(x*10 +a[i])%b; 	} 	lenc=1 ; 	while (c[lenc]==0 &&lenc<lena) 		lenc++; 	for (i=lenc;i<=lena;i++) 		cout <<c[i]; 	cout <<endl ; 	return  0 ; }  
高精除高精 这个复杂一点,要用到前面的好几种高精度运算
#include  <iostream>  #include  <cstring>  using  namespace  std ;int  a[101 ],b[101 ],c[101 ],d,i;void  init (int  a[]) 	string  s; 	cin >>s; 	a[0 ]=s.length(); 	for (i=1 ;i<=a[0 ];i++) 		a[i]=s[a[0 ]-i]-48 ; } void  print (int  a[]) 	int  i; 	if (a[0 ]==0 ) 	{ 		cout <<0 <<endl ; 		return ; 	} 	for (i=a[0 ];i>0 ;i--) 		cout <<a[i]; 	cout <<endl ; 	return ; } int  cmp (int  a[],int  b[]) 	int  i; 	if (a[0 ]>b[0 ]) 		return  1 ; 	if (a[0 ]<b[0 ]) 		return  -1 ; 	for (i=a[0 ];i>0 ;i--) 	{ 		if (a[i]>b[i]) 			return  1 ; 		if (a[i]<b[i]) 			return  -1 ; 	} 	return  0 ; } void  jian (int  a[],int  b[]) 	int  flag,i; 	flag=cmp(a,b); 	if (flag==0 ) 	{ 		a[0 ]=0 ; 		return ; 	} 	if (flag==1 ) 	{ 		for (i=1 ;i<=a[0 ];i++) 		{ 			if (a[i]<b[i]) 			{ 				a[i+1 ]--; 				a[i]+=10 ; 			} 			a[i]-=b[i]; 		} 		while (a[0 ]>0 &&a[a[0 ]]==0 ) 			a[0 ]--; 		return ; 	} } void  numcpy (int  p[],int  q[],int  det) 	for (int  i=1 ;i<=p[0 ];i++) 		q[i+det-1 ]=p[i]; 	q[0 ]=p[0 ]+det-1 ; } void  chugao (int  a[],int  b[],int  c[]) 	int  i,tmp[101 ]; 	c[0 ]=a[0 ]-b[0 ]+1 ; 	for (i=c[0 ];i>0 ;i--) 	{ 		memset (tmp,0 ,sizeof (tmp)); 		numcpy(b,tmp,i); 		while (cmp(a,tmp)>=0 ) 		{ 			c[i]++; 			jian(a,tmp); 		} 	} 	while (c[0 ]>0 &&c[c[0 ]]==0 ) 		c[0 ]--; 	return ; } int  main () 	memset (a,0 ,sizeof (a)); 	memset (b,0 ,sizeof (b)); 	memset (c,0 ,sizeof (c)); 	init(a); 	init(b); 	chugao(a,b,c); 	print(c); 	print(a); 	return  0 ; } 
高精乘方 #include <iostream>  #include <string.h>  #include <stdio.h>  using  namespace  std ;void  change (int  m,char   a[])              int  t=m;    for (int  i=0 ; t;i++){    a[i]=t%10 +48 ;    t/=10 ;    } } void  reverse (char   str[],int  l)     char  temp;    for (int  i=0 ;i<=l/2 ;i++)    {        temp=str[i];        str[i]=str[l-i];        str[l-i]=temp;    } } void  mul (int  m,int  n,char   result[])              char  a[20 ]={0 };    int   c[5000 ]={0 };    int  la,lr;    if (n==0  || m==1 ){result[0 ]='1' ;return  ;}    change(m,a);               la=strlen (a)-1 ;             lr=la;    strcpy (result,a);           int  i,j,k,l;    for (i=2 ;i<=n;i++){              memset (c,0 ,sizeof (c));    for (j=0 ;j<=la;j++)                 for (k=0 ;k<=lr;k++){       c[j+k]+=(a[j]-48 )*(result[k]-48 );       c[j+k+1 ]+=c[j+k]/10 ;       c[j+k]%=10 ;     }     l=k+j+1 ;          while (c[l]==0 )l--;        memset (result,0 ,sizeof (result));    for (j=0 ;j<=l;j++)result[j]=c[j]+'0' ;    lr=l;         }   reverse(result,lr);     } int  main ()   int  m,n;   while (scanf ("%d%d" ,&m,&n),m&&n)   {       char   result[5000 ]={0 };             if (n==0  ||m==1 ) result[0 ]='1' ;       mul(m,n,result);       printf ("%s\n" ,result);   }   return  0 ; } 
高精度取模 这个就十分简单了,都不用记录商
#include  <bits/stdc++.h>  using  namespace  std ;string  s;long  long  k=0 ,a,b,i;bool  flag;int  main ()     cin >>s>>b;     for (int  i=0 ;i<s.size();i++)     {         a=a*10 +s[i]-'0' ;         a%=b;     }     cout <<a;     return  0 ; } 
当然还有大佬用的重载运算符操作 这个东西我就真的不会了
直接上个实例吧
高精度的GCD(最大公约数)
#include  <cstdio>  #include  <cstring>  #include  <algorithm>  #define  rep(i,l,r) for (int i=l;i<=r;++i) const  int  Mx=1252 ,MOD=100000000 ;struct  BIGN {	int  a[Mx+10 ]; 	BIGN(){memset (a,0 ,sizeof  a);} 	int  &operator  [](int  i){return  a[i];} 	void  operator  /=(int  x){  		for  (int  i=Mx;i>=1 ;--i) 			a[i-1 ]+=a[i]%x*MOD,a[i]/=x; 		} 	void  operator  -=(BIGN &b){  		for  (int  i=1 ;i<Mx;++i) 			a[i]=a[i]-b[i]+(a[i-1 ]+MOD)/MOD -1 ,a[i-1 ]=(a[i-1 ]+MOD)%MOD; 		} 	void  operator  *=(int  x){  		for  (int  i=1 ;i<Mx;++i) 			a[i]=a[i]*x+a[i-1 ]/MOD,a[i-1 ]%=MOD; 		} 	bool  operator  <(BIGN &b){  		for  (int  i=Mx;i>=1 ;--i) 			if  (a[i]!=b[i]) return  a[i]<b[i]; 		return  false ; 		} 	bool  iszero ()  		for  (int  i=1 ;i<Mx;++i) if  (a[i]!=0 ) return  false ; 		return  true ; 		} 	void  read ()  		char  tp[10005 ]={'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' ,'0' }; 		scanf ("%s" ,tp+8 ); 		int  len=strlen (tp+1 ),p=1 ; 		while  (len-8 *p+1 >0 ) 			scanf (tp+len-8 *p+++1 ,"%8d" ,&a[p]); 		} 	void  print ()  		int  p=Mx; 		while  (!a[p]&&p>0 ) p--; 		printf ("%d" ,a[p--]); 		while  (p>0 ) printf ("%08d" ,a[p--]); 		printf ("\n" ); 		} }; BIGN gcd (BIGN x,BIGN y)  {	int  g=0 ;bool  x1,y1; 	while  (!x.iszero() && !y.iszero()){ 		x1=!(x[1 ]&1 ),y1=!(y[1 ]&1 ); 		if  (x1 && y1){g++;x/=2 ,y/=2 ;}else  		if  (x1 || y1){if  (x1) x/=2 ;else  y/=2 ;}else  		if  (y<x) x-=y;else  y-=x; 		} 	if  (x<y) x=y; 	while  (g--) x*=2 ; 	return  x; } BIGN a,b; int  main () 	a.read(); 	b.read(); 	gcd(a,b).print(); } 
懒人专用 __int64 其实是上面第一种忘得差不多了,第二种还不会
不过针对 GCC 和 VC ,这个东西是有差别的
主要是输入啦
VC6.0  的 64 位整数分别叫做 __int64 与 unsigned __int64 ,其范围分别是[-2^63, 2^63)与[0,2^64),即 -9223372036854775808 ~ 9223372036854775807 与 0 ~ 18446744073709551615 (约 1800 亿亿)。对 64 位整数的运算与 32 位整数基本相同,都支持四则运算与位运算等。当进行 64 位与 32 位的混合运算时, 32 位整数会被隐式转换成 64 位整数。但是, VC 的输入输出与 __int64 的兼容就不是很好了,如果你写下这样一段代码:
__int64 a; cin >>a;cout <<a;
那么,在第2行会收到“ error C2679: binary '>>' : no operator defined which takes a right-hand operand of type '__int64' (or there is no acceptable conversion) ”的错误;在第3行会收到“ error C2593: 'operator <<' is ambiguous ”的错误。那是不是就不能进行输入输出呢?当然不是,你可以使用C的写法:
scanf ("%I64d" ,&a);printf ("%I64d" ,a);
就可以正确输入输出了。当使用 unsigned __int64 时,把 "I64d" 改为 "I64u" 就可以了。
OJ  通常使用 g++ 编译器。其 64 位扩展方式与 VC 有所不同,它们分别叫做 long long 与 unsigned long long 。处理规模与除输入输出外的使用方法同上。对于输入输出,它的扩展比VC好。既可以使用
long  long  a;cin >>a;cout <<a;
也可以使用
scanf ("%lld" ,&a);printf ("%lld" ,a);
使用无符号数时,将 "%lld" 改成 "%llu" 即可。
1、作为一个特例,如果你使用的是 Dev-C++ 的 g++ 编译器,它使用的是 “%I64d” 而非 “%lld” 。
2、注意: __int64 是两个短的下划线
最后补充一个 __int128 和 __uint128 PS:这玩意只有 Linux 可以用 定义方式 __int64 是一样的
只是这玩意还不能用 cin 和 cout 进行读入读出( scanf 和 printf 也不行)
所幸现在的 oj 基本上都是 linux 系统的
所以只能抄一个读入读出代码了
#include  <bits/stdc++.h>  using  namespace  std ;inline  __int128 read ()     __int128 x=0 ,f=1 ;     char  ch=getchar();     while (ch<'0' ||ch>'9' ){         if (ch=='-' )             f=-1 ;         ch=getchar();     }     while (ch>='0' &&ch<='9' ){         x=x*10 +ch-'0' ;         ch=getchar();     }     return  x*f; } inline  void  print (__int128 x)     if (x<0 ){         putchar ('-' );         x=-x;     }     if (x>9 )         print(x/10 );     putchar (x%10 +'0' ); } int  main (void )     __int128 a = read();     __int128 b = read();     print(a + b);     cout <<endl ;     return  0 ; } 
关于高精度的算法我知道的就这些了,当然你如果学的是 python 好吧,以上东西你不需要