C++高精度模板

原文地址:http://blog.csdn.net/wall_f/article/details/8373395c++

原文只附代碼,沒有解析,本文增長了一些對代碼的解釋算法

請注意:本模板不涉及實數運算與負數運算,使用減法a-b時請保證, a >= b;全部用本模板來轉化的數需保證a >0 && a無小數部分。數組


引:
題目中涉及到高精度運算在信息學競賽中並很多見,不少題目得不到全分就是由於選手不會寫高精度模板。儘管AC太高精度(+,*,-,//除法麻煩一點)模板題,可是對於將高精度寫入結構體使得能夠正常運算的bign模板,不少選手只是有所聽聞而不會寫。其實寫起來並不難,只是將原來那些模板題寫入運算符重載便可markdown

建議背下來,OI比賽中指不定就撞上了,現推也能夠,可是比較慢,至少保證熟練函數

運算涉及
Bool型:== 、> 、< 、 >= 、 <= 、 !=
賦值語句:= 、 +=、 -=、 *=、 /=、 %=
運算符:+ 、- 、 * 、 /、 %this

其中 (?)= 賦值運算符的重載最爲好寫,直接調用已經重載完成的(?)運算符,再返回當前this。(? includes + - / %)spa

其次即是bool型。> < 分別用字符串的比較的比較方式重載,其他的只須要將它們組合一下。例如 == : !(>) && !(<)。.net

難點在於除法運算符的重載指針

咱們定義一個結構體包含一個整型int(長度)與數組s(存每一位)組成,其中數組是反着存的。code


#include <bits/stdc++.h> 

using namespace std;

const int MAXN = 5005;  

struct bign  
{  
    int len, s[MAXN];  
    bign ()  //初始化
    {  
        memset(s, 0, sizeof(s));  
        len = 1;  
    }  
    bign (int num) { *this = num; }  
    bign (const char *num) { *this = num; }  //讓this指針指向當前字符串
    bign operator = (const int num)  
    {  
        char s[MAXN];  
        sprintf(s, "%d", num);  //sprintf函數將整型映到字符串中
        *this = s;  
        return *this;  //再將字符串轉到下面字符串轉化的函數中
    }  
    bign operator = (const char *num)  
    {  
        for(int i = 0; num[i] == '0'; num++) ;  //去前導0 
        len = strlen(num);  
        for(int i = 0; i < len; i++) s[i] = num[len-i-1] - '0'; //反着存
        return *this;
    }  
    bign operator + (const bign &b) const //對應位相加,最爲簡單
    {  
        bign c;  
        c.len = 0;  
        for(int i = 0, g = 0; g || i < max(len, b.len); i++)  
        {  
            int x = g;  
            if(i < len) x += s[i];  
            if(i < b.len) x += b.s[i];  
            c.s[c.len++] = x % 10;  //關於加法進位
            g = x / 10;  
        }  
        return c;  
    }  
    bign operator += (const bign &b)  //如上文所說,此類運算符皆如此重載
    {  
        *this = *this + b;  
        return *this;  
    }  
    void clean()  //因爲接下來的運算不能肯定結果的長度,先大而估之而後再查
    {  
        while(len > 1 && !s[len-1]) len--;  //首位部分‘0’故刪除該部分長度
    }   
    bign operator * (const bign &b) //乘法重載在於列豎式,再將豎式中的數轉爲抽象,便可看出運算法則。
    {  
        bign c;  
        c.len = len + b.len;  
        for(int i = 0; i < len; i++)  
        {  
            for(int j = 0; j < b.len; j++)  
            {  
                c.s[i+j] += s[i] * b.s[j];//不妨列個豎式看一看
            }  
        }  
        for(int i = 0; i < c.len; i++) //關於進位,與加法意同 
        {  
            c.s[i+1] += c.s[i]/10;
            c.s[i] %= 10;
        }  
        c.clean();  //咱們估的位數是a+b的長度和,但可能比它小(1*1 = 1)
        return c;  
    }  
    bign operator *= (const bign &b)  
    {  
        *this = *this * b;  
        return *this;  
    }  
    bign operator - (const bign &b)  //對應位相減,加法的進位改成借1
    {  //不考慮負數
        bign c;  
        c.len = 0;  
        for(int i = 0, g = 0; i < len; i++)  
        {  
            int x = s[i] - g;  
            if(i < b.len) x -= b.s[i];  //可能長度不等
            if(x >= 0) g = 0;  //是否向上移位借1
            else  
            {  
                g = 1;  
                x += 10;  
            }  
            c.s[c.len++] = x;  
        }  
        c.clean();  
        return c;   
    }  
    bign operator -= (const bign &b)  
    {  
        *this = *this - b;  
        return *this;  
    }  
    bign operator / (const bign &b)  //運用除是減的本質,不停地減,直到小於被減數
    {  
        bign c, f = 0; //可能會在使用減法時出現高精度運算 
        for(int i = len-1; i >= 0; i--)  //正常順序,從最高位開始
        {  
            f = f*10;  //上面位的剩餘到下一位*10
            f.s[0] = s[i];  //加上當前位
            while(f >= b)  
            {  
                f -= b;  
                c.s[i]++;  
            }  
        }  
        c.len = len;  //估最長位
        c.clean();  
        return c;  
    }  
    bign operator /= (const bign &b)  
    {  
        *this  = *this / b;  
        return *this;  
    }  
    bign operator % (const bign &b)  //取模就是除完剩下的
    {  
        bign r = *this / b;  
        r = *this - r*b;  
        r.clean();
        return r;  
    }  
    bign operator %= (const bign &b)  
    {  
        *this = *this % b;  
        return *this;  
    }  
    bool operator < (const bign &b) //字符串比較原理 
    {  
        if(len != b.len) return len < b.len;  
        for(int i = len-1; i != -1; i--)  
        {  
            if(s[i] != b.s[i]) return s[i] < b.s[i];  
        }  
        return false;  
    }  
    bool operator > (const bign &b)  //同理
    {  
        if(len != b.len) return len > b.len;  
        for(int i = len-1; i != -1; i--)  
        {  
            if(s[i] != b.s[i]) return s[i] > b.s[i];  
        }  
        return false;  
    }  
    bool operator == (const bign &b)  
    {  
        return !(*this > b) && !(*this < b);  
    }  
    bool operator != (const bign &b)  
    {  
        return !(*this == b);  
    }  
    bool operator <= (const bign &b)  
    {  
        return *this < b || *this == b;  
    }  
    bool operator >= (const bign &b)  
    {  
        return *this > b || *this == b;  
    }  
    string str() const  //將結果轉化爲字符串(用於輸出)
    {  
        string res = "";  
        for(int i = 0; i < len; i++) res = char(s[i]+'0')+res;  
        return res;  
    }  
};  

istream& operator >> (istream &in, bign &x) //重載輸入流 
{  
    string s;  
    in >> s;  
    x = s.c_str();  //string轉化爲char[]
    return in;  
}  

ostream& operator << (ostream &out, const bign &x)  //重載輸出流
{  
    out << x.str();  
    return out;  
}

int main()
{
    bign a;//除了聲明外其餘如整型般使用
    //……
    return 0;
}

感謝原做者。

不妨運用一下:
luogu P1601 A+B Problem(高精) https://www.luogu.org/problem/show?pid=1601
luogu P2142 高精度減法 https://www.luogu.org/problem/show?pid=2142
luogu P1303 A*B Problem https://www.luogu.org/problem/show?pid=1303
luogu P1480 A/B Problem https://www.luogu.org/problem/show?pid=1480

不妨思考一下其餘高精度運算:
luogu:P2293 [HNOI2004]高精度開根 https://www.luogu.org/problem/show?pid=2293

高精度模板至此結束。
箜瑟_qi 2017.04.08 9:53

相關文章
相關標籤/搜索