大整数运算

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;
}
原文地址:https://www.cnblogs.com/youxin/p/3294146.html