C/C++中的int类型能表示的范围是-2E31-2E31–1。unsigned类型能表示的范围是0-2E32–1,即 0-4294967295。所以,int和unsigned类型变量,都不能保存超过10位的整数。有时我们需要参与运算的数,可能会远远不止10 位,例如,可能需要保留小数点后面100位(比如求π的值),那么,即便使用能表示很大数值范围的double变量,但是由于double变量只有64位,所以还是不可能达到精确到小数点后面100位这样的精度。
double变量的精度也不足以表示一个100位的整数。一般我们称这种基本数据类型无法表示的整数为大整数。如何表示和存放大整数呢?基本的思想就是:用数组存放和表示大整数。一个数组元素,存放大整数中的一位。
那么,如何解决类似大整数这样的高精度计算问题呢?
大数是指计算的数值非常大或者对运算的精度要求非常高,用已知的数据类型无法表示的数值。
设计思想如下:
1.用数组模拟大数的运算。
2.开一个比较大的整型数组,数组的元素代表数组的某一位或者某几位。
3.通过对数组元素的运算模拟大数的运算。
4.将数组输出。
大整数加法
问题:求两个不超过200位的非负整数的和
#include <stdio.h> #include <string.h> #define MAX_LEN 200 int an1[MAX_LEN+10]; int an2[MAX_LEN+10]; char szLine1[MAX_LEN+10]; char szLine2[MAX_LEN+10]; int main(void) { scanf("%s", szLine1); scanf("%s", szLine2); int i, j; memset( an1, 0, sizeof(an1)); memset( an2, 0, sizeof(an2)); int nLen1 = strlen( szLine1); for( j = 0, i = nLen1 - 1;i >= 0 ; i --) an1[j++] = szLine1[i] - '0'; int nLen2 = strlen(szLine2); for( j = 0, i = nLen2 - 1;i >= 0 ; i --) an2[j++] = szLine2[i] - '0'; for( i = 0;i < MAX_LEN ; i ++ ) { an1[i] += an2[i]; //逐位相加 if( an1[i] >= 10 ) { //看是否要进位 an1[i] -= 10; an1[i+1] ++; //进位 ,可以另外设置一个变量takeOver } } for( i = MAX_LEN; (i >= 0) && (an1[i] == 0); i -- ) ; if(i>=0) for( ; i >= 0; i--) printf("%d", an1[i]); else printf("0"); return 0; }
大整数乘法
问题:求两个不超过200 位的非负整数的积。输入数据有两行,每行是一个不超过200 位的非负整数,没有多余的前导0。输出要求一行,即相乘后的结果。结果里不能有多余的前导0,即如果结果是342,那么就不能输出为0342。
比如说要计算 835×49:
规律:一个数的第i位和另一个数的第j位相乘所得的数,一定是要累加到结果的第i+j位上。这里i,j都是从右往左,从0开始数。
#include <stdio.h> #include <string.h> #define MAX_LEN 200 int main(void) { int i, j; int len1,len2; int a[MAX_LEN+10],b[MAX_LEN+10],c[MAX_LEN*2+10]; char str1[MAX_LEN+10],str2[MAX_LEN+10]; for(i=0;i<MAX_LEN+10;i++) a[i]=b[i]=0; for(i=0;i<MAX_LEN*2+10;i++) c[i]=0; gets(str1); //按字符串形式读入第一个整数 gets(str2); len1=strlen(str1); for(j=0,i=len1-1; i>=0; i--)//把数字倒过来 a[j++]=str1[i]-'0'; len2=strlen(str2); for(j=0,i=len2-1; i>=0; i--)//倒转第二个整数 b[j++]=str2[i]-'0'; for(i=0; i<len2; i++)//用第二个数乘以第一个数,每次一位 { for(j=0; j<len1; j++) c[i+j]+= b[i]*a[j]; //先乘起来,后面统一进位 } for(i=0; i<MAX_LEN*2; i++)//循环统一处理进位问题 { if(c[i]>=10) { c[i+1]+=c[i]/10; c[i]%=10; } } for(i=MAX_LEN*2; (c[i]==0)&&(i>=0); i--);//跳过高位的0 if(i>=0) for(;i>=0;i--) printf("%d", c[i]); else printf("0"); return 0; }
更多:
http://blog.csdn.net/lishuhuakai/article/details/8972275
http://wenku.baidu.com/view/a89d2d1a10a6f524ccbf857f.html
http://wenku.baidu.com/view/290cbe0fbb68a98271fefaf3.html
http://wenku.baidu.com/view/f0ef513467ec102de2bd89b1.html
【转】ACM-ICPC 大整数计算模板函数 -biginh.h
/*高精度计算模板函数 2010-12-6 本文件名 biginh.h
整数 大于 2^64-1, 称为大整数,要用高精度计算
例如 a=123444455556666777788889999 是27位数
用数组表示它 ,最低4位用 a[1]=9999表示,称a[1]是10000进制数的
个位数。
a[2]=8888;a[3]=7777,a[4]=6666,a[5]=5555,a[6]=4444,a[7]=123;
a[0]=7;表示它是万进制 数的7位数。
Base=10000进制 。
大整数用字符串读入, 再用函数 tran 转为数组
本文件有下列函数
trans,comp,PN,copy,add,sub,mult,mult,Div
程序中用到高精度计算时,
(1)将本文件复制到 int main()的前面, 然后将不需要的函数删除,也可以不删除.
(2) 也可以加上 #include<bigint.h>
例如 hdu1002 A + B Problem II,只用到加法,可将sub,mult,mult,Div删除
要用高精度计算的题
hdu1002 A + B Problem II
hdu1502 Regular Words
hdu1042 n! n<=10000
hdu1133 Buy the Ticket http://acm.hdu.edu.cn/showproblem.php?pid=1133
zju2061 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2061
hdu1134 Game of Connections
catalan数 h[1]=1,h[n]=h[n-1]*(4n-2) /(n+1) ,n<=100
hdu1250 Hat's Fibonacci http://acm.hdu.edu.cn/showproblem.php?pid=1250
pku2084 Game of Connections = hdu1134
pku2515 Birthday Cake
计算 1+2^M +...+n^M, n<=10^41, M<=100
pku1220 NUMBER BASE CONVERSION
pku2680 Computer Transformation
pku3181 Dollar Dayz
pku3199 Uncle Jack
pku3324 Lucas-Lehmer Test
pku3331 The Idiot of the Year Contest
*/
con st int Base=10000; //万进制 int 最大,如果只用 +,-,可加大Base=1000000000 int ONE[ ]={1,1}; //大整数 1 int ZERO[ ]={1,0}; //大整数 0 void trans(char *ch,int *A); //串->数 base=10000,A[1]是最低位,A[0]是位数(段数) int comp(int *a, int *b);//大整数比较大小 void PN(int *a);//printf 大整数a void copy(int *a, int *b);// a=b void add(int *a,int *b,int *c);//大整数+大整数 c=a+b void sub(int *a, int *b, int *c);//大整数a-大整数 b,a>b void mult(int *a, int b, int *d);//大整数*整数 c=a*b void mult(int *a,int *b,int *c);//大整数*大整数 c=a*b int Div(int *a,int b,int *c);// c=a/b return k=a%b /*串-->数 base=10000,A[1]是最低位,A[0]是位数(段数) 串12355558888-->A[1]=8888,A[2]=5555,A[3]=123 A[0]=3,每段 seg=4个数字 */ void trans(char *ch,int *A) {int L,i,j,k,s,i9,seg=4; if(Base==1000000)seg=6; L=strlen(ch); s=L-seg;k=1; for(i=s;i>=0;i-=seg,k++) {i9=i+seg;A[k]=ch[i]-'0'; for(j=i+1;j<i9;j++)A[k]=A[k]*10+ch[j]-48; } i+=seg; A[k]=0; for(j=0;j<i;j++)A[k]=A[k]*10+ch[j]-48; if(A[k])A[0]=k;else A[0]=k-1; } /*tran的另1中写法 串-->数 base=10000,A[1]是最低位,A[0]是位数(段数) 串12355558888-->A[1]=8888,A[2]=5555,A[3]=123 A[0]=3,每段 seg=4个数字 */ void trans2(char *ch,int *A) {int L,i,j,k,s,seg=4; if(Base==1000000)seg=6; L=strlen(ch); k=L%seg;if(k==0)k=seg; s=A[0]=(L+seg-1)/seg;//10000进制 s位数 A[s]=0; for(i=0;i<k;i++)A[s]=A[s]*10+ch[i]-'0'; for(j=s-1;j>=1;j--,i+=4) { A[j]=0; for(k=i;k<i+seg;k++)A[j]=A[j]*10+ch[k]-'0'; } } //大整数比较大小 int comp(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 >= 1; i--) { if (a[i] > b[i])return 1; if (a[i] < b[i])return -1; } return 0; } void PN(int *a){ int i;// 输出 "%04d" 10000进制, "%05d" 100000进制,"%06d" 1000000进制, printf("%d", a[a[0]]); for(i=a[0]-1;i>=1;i--)printf("%04d", a[i]);printf(" "); } void copy(int *a, int *b) { int i; //a=b for (i = 0;i<= b[0]; ++i)a[i] = b[i]; } //大整数+大整数 c=a+b,Base进制 ,Base=10000 // c[0] 是段数,c[1]是最低位。 // 例9912348888, c[0]=3,c[1]=8888,c[2]=1234,c[3]=99 void add(int *a, int *b, int *c) { int s, i,t,p,d[1000]; if((b[0]==1)&&(b[1]==0)){copy(c,a);return;} if((a[0]==1)&&(a[1]==0)){copy(c,b);return;} if (a[0] >= b[0]) { copy(c,a);copy(d,b);} else { copy(c,b);copy(d,a);} s=c[0];t=d[0];//c[0]>=d[0] c[s + 1] = 0; for (i = 1; i <= t; i++) {c[i]+=d[i]; if (c[i]>=Base){c[i]-=Base;c[i+1]++;} } for (; i <= s; i++){if(c[i]>=Base){c[i] -= Base;c[i+1]++;} else break;} if (c[s+1]>0)c[0] = s + 1;//处理最后一位 } //大整数a-大整数 b, a>b,c=a-b void sub(int *a, int *b, int *c) { int i, j,p=0; if(b[0]==1&&(b[1]==0)){copy(c,a);return;} if(comp(a,b)<=0){copy(c,ZERO);return;} if(comp(a,ZERO)==0){copy(c,ZERO);return;} for (i = 1; i <= b[0]; i++) { c[i] = a[i] - b[i] - p; if (c[i] < 0) { c[i] += Base; p = 1; } else p = 0; } for (; i <= a[0]; i++) { c[i] = a[i] - p; if (c[i] < 0) { c[i] += Base; p = 1; } else p = 0; } for(i=a[0];i>=1;i--){ if (c[i]) {c[0] = i;break;} } } //大整数a乘常数 b b<Base, d=a*b void mult(int *a,int b,int *d) { int w, i,p; if(b==1){copy(d,a);return;} if((b==0)||(a[0]==1&&a[1]==0)){d[0]=1;d[1]=0;return;} w = a[0]; p = 0; // for (i = 1; i <= w; i++) { d[i] = a[i] * b + p; if (d[i] >= Base) { p = d[i] / Base; d[i] %= Base;}else p=0; } if (p) {w++;d[w] = p;} d[0] = w; } //大整数a*大整数 b, c=a*b void mult(int *a,int *b,int *c) {int i,j,s,m,n,k,p;//Base<=10000 m=a[0];n=b[0];k=m+n-1; /*m位数 *n位数 = m+n-1位 或 m+n 位数 实例 12345678*123456789012 =1524157764056090136 a[0]=2 a[1]=5678;a[2]=1234; b[0]=3 b[1]=9012; b[2]=5678;b[3]=1234; */ p=0; for(i=0;i<=k;i++)c[i]=0;c[i]=0; // a[1],a[2]....,a[m] // b[1] // c[1],c[2],...,c[m] for(j=1;j<=n;j++) { s=j; if(b[j])for(i=1;i<=m;i++,s++) {c[s]+=a[i]*b[j]; if(c[s]>=Base){c[s+1]+=c[s]/Base;c[s]%=Base;} } } for(i=1;i<=k;i++)if(c[i]>=Base) { c[i+1]+=c[i]/Base;c[i]%=Base; } if(c[k+1])k++; c[0]=k; } // c=a/b k=a%b 大整数/ 常数b ,b<Base int Div(int *a,int b,int *c) {int i,j,s,t; int k=0,q; // Base<=10000 // long long k=0,q;// if Base>=100000 if(comp(a,ZERO)==0){copy(c,ZERO);return 0;} for(i=a[0];i>=1;i--) { q=k*Base+a[i]; c[i]=q/b;k=q%b; } if(c[a[0]]==0){ c[0]=a[0]-1;} else c[0]=a[0]; return k; }
网上面的模板1:
#include <map> #include <set> #include <cmath> #include <queue> #include <stack> #include <vector> #include <bitset> #include <string> #include <string.h> #include <limits.h> #include <stdio.h> #include <iostream> #include <algorithm> using namespace std; class BigNum; istream& operator>>(istream&, BigNum&); ostream& operator<<(ostream&, BigNum&); #define MAXN 9999 #define MAXSIZE 100000 #define DLEN 4 class BigNum { public: int a[MAXSIZE]; int len; public: BigNum(){len = 1;memset(a,0,sizeof(a));} BigNum(const int); BigNum(const char*); BigNum(const BigNum &); BigNum &operator=(const BigNum &); friend istream& operator>>(istream&, BigNum&); friend ostream& operator<<(ostream&, BigNum&); BigNum operator+(const BigNum &) const; BigNum operator-(const BigNum &) const; BigNum operator*(const BigNum &) const; BigNum operator/(const int &) const; BigNum operator^(const int &) const; int operator%(const int &) const; bool operator>(const BigNum & T)const; bool operator==(const BigNum & T)const; bool operator==(const int & t)const; bool operator>(const int & t)const; }; istream& operator>>(istream & in, BigNum & b) { char ch[MAXSIZE*4]; int i = -1; in>>ch; int l=strlen(ch); int count=0,sum=0; for (i=l-1;i>=0;) { sum = 0; int t=1; for (int j=0;j<4&&i>=0;j++,i--,t*=10) { sum+=(ch[i]-'0')*t; } b.a[count]=sum; count++; } b.len =count++; return in; } ostream& operator<<(ostream& out, BigNum& b) { int i; cout << b.a[b.len - 1]; for (i = b.len - 2 ; i >= 0 ; i--) { cout.width(DLEN); cout.fill('0'); cout << b.a[i]; } return out; } BigNum::BigNum(const int b) { int c,d = b; len = 0; memset(a,0,sizeof(a)); while (d > MAXN) { c = d - (d / (MAXN + 1)) * (MAXN + 1); d = d / (MAXN + 1); a[len++] = c; } a[len++] = d; } BigNum::BigNum(const char*s) { int t,k,index,l; memset(a,0,sizeof(a)); l=strlen(s); len=l/DLEN; if (l%DLEN)len++; index=0; for (int i=l-1;i>=0;i-=DLEN) { t=0;k=i-DLEN+1; if (k<0)k=0; for (int j=k;j<=i;j++) t=t*10+s[j]-'0'; a[index++]=t; } } BigNum::BigNum(const BigNum & T) : len(T.len) { int i; memset(a,0,sizeof(a)); for (i = 0 ; i < len ; i++) a[i] = T.a[i]; } BigNum & BigNum::operator=(const BigNum & n) { len = n.len; memset(a,0,sizeof(a)); for (int i = 0 ; i < len ; i++) a[i] = n.a[i]; return *this; } BigNum BigNum::operator+(const BigNum & T) const { BigNum t(*this); int i,big; big = T.len > len ? T.len : len; for (i = 0 ; i < big ; i++) { t.a[i] +=T.a[i]; if (t.a[i] > MAXN) { t.a[i + 1]++; t.a[i] -=MAXN+1; } } if (t.a[big] != 0) t.len = big + 1; else t.len = big; return t; } BigNum BigNum::operator-(const BigNum & T) const { int i,j,big; bool flag; BigNum t1,t2; if (*this>T) { t1=*this; t2=T; flag=0; } else { t1=T; t2=*this; flag=1; } big=t1.len; for (i = 0 ; i < big ; i++) { if (t1.a[i] < t2.a[i]) { j = i + 1; while (t1.a[j] == 0) j++; t1.a[j--]--; while (j > i) t1.a[j--] += MAXN; t1.a[i] += MAXN + 1 - t2.a[i]; } else t1.a[i] -= t2.a[i]; } t1.len = big; while (t1.a[len - 1] == 0 && t1.len > 1) { t1.len--; big--; } if (flag)t1.a[big-1]=0-t1.a[big-1]; return t1; } BigNum BigNum::operator*(const BigNum & T) const { BigNum ret; int i,j,up; int temp,temp1; for (i = 0 ; i < len ; i++) { up = 0; for (j = 0 ; j < T.len ; j++) { temp = a[i] * T.a[j] + ret.a[i + j] + up; if (temp > MAXN) { temp1 = temp - temp / (MAXN + 1) * (MAXN + 1); up = temp / (MAXN + 1); ret.a[i + j] = temp1; } else { up = 0; ret.a[i + j] = temp; } } if (up != 0) ret.a[i + j] = up; } ret.len = i + j; while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; return ret; } BigNum BigNum::operator/(const int & b) const { BigNum ret; int i,down = 0; for (i = len - 1 ; i >= 0 ; i--) { ret.a[i] = (a[i] + down * (MAXN + 1)) / b; down = a[i] + down * (MAXN + 1) - ret.a[i] * b; } ret.len = len; while (ret.a[ret.len - 1] == 0 && ret.len > 1) ret.len--; return ret; } int BigNum::operator %(const int & b) const { int i,d=0; for (i = len-1; i>=0; i--) { d = ((d * (MAXN+1))% b + a[i])% b; } return d; } BigNum BigNum::operator^(const int & n) const { BigNum t,ret(1); int i; if (n<0)exit(-1); if (n==0)return 1; if (n==1)return *this; int m=n; while (m>1) { t=*this; for ( i=1;i<<1<=m;i<<=1) { t=t*t; } m-=i; ret=ret*t; if (m==1)ret=ret*(*this); } return ret; } bool BigNum::operator>(const BigNum & T) const { int ln; if (len > T.len) return true; else if (len == T.len) { ln = len - 1; while (a[ln] == T.a[ln] && ln >= 0) ln--; if (ln >= 0 && a[ln] > T.a[ln]) return true; else return false; } else return false; } bool BigNum::operator==(const BigNum & T) const { int ln; if (len != T.len) return false; else { ln = len - 1; while (a[ln] == T.a[ln] && ln-- ); if (ln < 0) return true; else return false; } } bool BigNum::operator >(const int & t) const { BigNum b(t); return *this>b; } bool BigNum::operator==(const int & t) const { BigNum b(t); return *this==b; } // 求n的阶乘 int main() { int n,i; BigNum S; cin>>n; S=1; for(i=1;i<=n;i++) S=S*i; cout<<S<<endl; return 0; }