• 大整数运算


    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;
    }
  • 相关阅读:
    Outlook 2003 最小化到系统托盘方法 [转]
    Sql Server 得到当月第一天
    禁止用户对系统数据库表的SELECT权限
    解决IE二级链接无法打开故障
    服务器安全设置全攻略
    使用TSQL脚本在SQL Server创建角色,并给角色赋予相应权限
    Redis内部阻塞式操作有哪些?
    UML和OO
    PetShop 4 详解(转载)
    Blog开通了
  • 原文地址:https://www.cnblogs.com/youxin/p/3294146.html
Copyright © 2020-2023  润新知