1. 程式人生 > >高精度——壓位的思想及應用

高精度——壓位的思想及應用

是我 c const memset name mes res -- 希望 string

本文作者frankchenfu,blogs網址http://www.cnblogs.com/frankchenfu/,轉載請保留此文字。
這裏我們簡單介紹一下高精度的計算。
我們都知道在Cpp/C/Pas等語言中,整數最大能儲存\(2^{64} -1\),超過這個範圍就表示不了了(不包括個別支持int128的編譯器)。這個時候,我們如果希望把這些整數存儲下來,就需要用到高精度的算法和思想。高精度就是像小學學過的豎式運算一樣的(除法除外)。然後就直接模擬即可。除法一位一位地試商即可。
接下來我們發現就是一位一位地加減很慢,我們考慮如何把它加快速度(減小常數)。如果你有學習過關於bitset的相關知識,那你肯定對壓位的方法不陌生。我們把十進制位中的每4~8位並在一起(筆者一般壓4位,因為乘法時不會超過int

的範圍),然後照樣加減,最後並不影響答案,但是要註意輸出。對於除法,我們此時發現枚舉\(10^4\)\(10^8\)太慢了,註意到單調性,於是我們考慮二分試商,這樣就也可以在\(log_2 BASE\)的時間之內求出來了。
註意初始化、賦值和輸出。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef int ll;

struct bign//big number
{
//init
    static const int BASE=(int)1e4,POW=4;
    static const int MAXLEN=20010;
    ll num[MAXLEN];//num[0]=length of the big number
    bign(int tp=0)
    {
        memset(num,tp,sizeof(num));
    }
    void clear()
    {
        memset(num,0,sizeof(num));
    }
    bool operator=(const char ch[])
    {
        int len=strlen(ch);
        for(int i=0;i<len;i++)
            num[(len-i-1)/POW+1]=num[(len-i-1)/POW+1]*10+ch[i]-‘0‘;
        num[0]=(len-1)/POW+1;
    }
    
//compare
    //big number
    bool operator<(const bign &rsh)const
    {
        if(num[0]!=rsh.num[0])
            return num[0]<rsh.num[0];
        for(int i=num[0];i;i--)
        {
            if(num[i]!=rsh.num[i])
                return num[i]<rsh.num[i];
        }
        return 0;
    }
    //int/long long 
    ll max(ll _x,ll _y)
    {
        return _x>_y?_x:_y;
    }
    ll min(ll _x,ll _y)
    {
        return _x<_y?_x:_y;
    }
    
//operator
    //add
    void operator+=(const bign &rsh)
    {
        num[0]=max(num[0],rsh.num[0]);
        for(int i=1;i<=num[0];i++)
        {
            num[i]+=rsh.num[i];
            num[i+1]+=num[i]/BASE;
            num[i]%=BASE;
        }
        while(num[num[0]+1]>0)
            num[0]++;
    }
    bign operator+(const bign &rsh)const
    {
        bign res=*this;res+=rsh;
        return res;
    }
    //subtract
    void operator-=(const bign &rsh)
    {
        for(int i=1;i<=num[0];i++)
        {
            num[i]-=rsh.num[i];
            while(num[i]<0)
            {
                num[i]+=BASE;
                num[i+1]--;
            }
        }
        while(num[num[0]]<=0&&num[0]>0)
            num[0]--;
    }
    bign operator-(const bign &rsh)const
    {
        bign res=*this;res-=rsh;
        return res;
    }
    //multiply
    bign operator*(const bign &rsh)const
    {
        bign res;
        res.num[0]=num[0]+rsh.num[0]-1;
        for(int i=1;i<=num[0];i++)
            for(int j=1;j<=rsh.num[0];++j)
                res.num[i+j-1]+=num[i]*rsh.num[j];
        for(int i=1;i<=res.num[0];i++)
        {
            res.num[i+1]+=res.num[i]/BASE;
            res.num[i]%=BASE;
        }
        while(res.num[res.num[0]+1]>0)
        {
            res.num[0]++;
            res.num[res.num[0]+1]+=res.num[res.num[0]]/BASE;
            res.num[res.num[0]]%=BASE;
        }
        return res;
    }
    void operator*=(const bign &rsh)
    {
        bign res=*this;res=res*rsh;
        *this=res;
    }
    //divide
    void operator/=(const ll &rsh)
    {
        for(int i=num[0];i>1;i--)
        {
            num[i-1]+=(num[i]%rsh*BASE);
            num[i]/=rsh;
        }
        num[1]/=rsh;
        while(num[0]>0&&num[num[0]]<=0)
            num[0]--;
    }
    bign operator/(const ll &rsh)const
    {
        bign temp=*this ;
        temp/=rsh;
        return temp;
    }
    
    void operator/=(const bign &rsh)
    {
        bign l,r=*this,tmp_one;tmp_one="1";
        l.num[0]=1;
        while(l<r)
        {
            bign mid=(l+r+tmp_one)/2;
            if(*this<(rsh*mid))
                r=mid-tmp_one;
            else
                l=mid;
        }
        *this=l;
    }
    bign operator/(const bign &rsh)const
    {
        bign res=*this;res/=rsh;
        return res;
    }
    //mod
    void operator%=(const bign &rsh)
    {
        bign res=*this;
        res=res-res/rsh*rsh;
        *this=res;
    }

    bign operator%(const bign &rsh)const
    {
        bign res=*this;res%=rsh;
        return res;
    }
};
ostream&operator<<(ostream &out,const bign &x)
{
    printf("%d",x.num[x.num[0]]);
    for(int i=x.num[0]-1;i;i--)
        printf("%04d",x.num[i]);
    return out;
}

高精度——壓位的思想及應用