高精度算法之大整數類

思想:

因爲編程語言提供的基本數值數據類型表示的數值範圍有限,不能知足較大規模的高精度數值計算,所以須要利用其餘方法實現高精度數值的計算,因而產生了大數運算。大數運算主要有加、減、乘三種方法。html

考慮用數組存儲整數,並模擬手算的方法進行加減乘除四則運算。爲了能像int同樣方便的使用大整數,能夠定義結構體,大整數類。ios

結構體BigInteger可用於存儲高精度非負整數。這裏存儲的方案是每8位存在一個數組的元素裏,所用base爲1億,也就是1e8這麼多,從低位向高位存儲c++

好比:123456789123456789 存儲爲| 23456789 |34567891 |12|在一個數組中。git

大數結構體:

代碼:

 1 struct BigInteger
 2 {
 3     static const int BASE = 100000000;
 4     static const int WIDTH = 8;
 5     vector<int> s;
 6 
 7     BigInteger(long long num = 0) {*this = num;}//構造函數
 8     BigInteger operator=(long long num)//賦值運算符
 9     {
10         s.clear();
11         do
12         {
13             s.push_back(num%BASE);
14             num /= BASE;
15         }while(num>0);
16         return *this;
17     }
18     BigInteger operator=(const string& str)//賦值運算符
19     {
20         s.clear();
21         int x,len = (str.length()-1)/WIDTH+1;
22         for(int i = 0;i<len;i++)
23         {
24             int end = str.length()-i*WIDTH;
25             int start = max(0,end-WIDTH);
26             sscanf(str.substr(start,end-start).c_str(),"%d",&x);
27             s.push_back(x);
28         }
29         return *this;
30     }
31 }

大數類的輸入輸出運算符重載:

還能夠重載「<<」和「>>」運算符,使用方便github

代碼:

 1 friend ostream& operator<<(ostream &out,const BigInteger& x)
 2     {
 3         out << x.s.back();
 4         for(int i = x.s.size()-2;i>=0;i--)
 5         {
 6             char buf[20];
 7             sprintf(buf,"%8d",x.s[i]);
 8             for(int j = 0;j<strlen(buf);j++)
 9             {
10                 out << buf[j];
11             }
12         }
13         return out;
14     }
15     friend istream& operator>>(istream &in,BigInteger& x)
16     {
17         string s;
18         if(!(in >> s)) return in;
19         x = s;
20         return in;
21     }

因爲c++的繼承機制,如今istream類和ostream類均可以使用它來輸出輸入大整數了編程

上述代碼中BASE是靜態成員變量,屬於這個類型而不屬於靜態對象,用static修飾數組

大數類的加法:

 1  BigInteger operator+(const BigInteger& b) const
 2     {
 3         BigInteger c;
 4         c.s.clear();
 5         for(int i = 0,g = 0;;i++)
 6         {
 7             if(g==0&&i>=s.size()&&i>=b.s.size())//當進位爲零而且加完了,退出。若是加完了進位不爲零,就繼續把進位補上,在退出
 8             {
 9                 break;
10             }
11             int x = g;//g爲進位數,滿一個BASE才向下進一位
12             if(i<s.size()) x+=s[i];
13             if(i<b.s.size()) x+=b.s[i];
14             c.s.push_back(x%BASE);//進位後本位上的數
15             g = x/BASE;//更新進位數
16         }
17         return c;
18     }
19     BigInteger operator+=(const BigInteger& b)
20     {
21         *this = *this+b;
22         return *this;
23     }

大數類的比較:

一開始就比較兩個數的位數,不相等直接返回,不然從後往前比(低位在前)。注意這是在沒有前導零的狀況下才能這樣比,有前導零最後一位還要單獨處理。編程語言

代碼:

bool operator<(const BigInteger& b) const
    {
        if(s.size()!=b.s.size())
        {
            return s.size()<b.s.size();
        }
        for(int i = s.size()-1;i>=0;i--)
        {
            if(s[i]!=b.s[i])
            {
                return s[i]<b.s[i];
            }
        }
        return false;
    }
    bool operator>(const BigInteger& b) const
    {
        return b<*this;
    }
    bool operator<=(const BigInteger& b) const
    {
        return !(b<*this);
    }
    bool operator>=(const BigInteger& b) const
    {
        return !(*this<b);
    }
    bool operator!=(const BigInteger& b) const
    {
        return (b< *this||*this<b);
    }
    bool operator==(const BigInteger& b) const
    {
        return !(b<*this)&&!(*this<b);
    }

這時依賴比較運算符的容器函數就能夠支持大整數類了。ide

代碼彙總:函數

 

  1 #include <cstdio>
  2 #include <iostream>
  3 #include <vector>
  4 #include <cstring>
  5 #include<set>
  6 #include<map>
  7 using namespace std;
  8 struct BigInteger
  9 {
 10     static const int BASE = 100000000;
 11     static const int WIDTH = 8;
 12     vector<int> s;
 13 
 14     BigInteger(long long num = 0) {*this = num;}//構造函數
 15     BigInteger operator=(long long num)//賦值運算符
 16     {
 17         s.clear();
 18         do
 19         {
 20             s.push_back(num%BASE);
 21             num /= BASE;
 22         }while(num>0);
 23         return *this;
 24     }
 25     BigInteger operator=(const string& str)//賦值運算符
 26     {
 27         s.clear();
 28         int x,len = (str.length()-1)/WIDTH+1;
 29         for(int i = 0;i<len;i++)
 30         {
 31             int end = str.length()-i*WIDTH;
 32             int start = max(0,end-WIDTH);
 33             sscanf(str.substr(start,end-start).c_str(),"%d",&x);
 34             s.push_back(x);
 35         }
 36         return *this;
 37     }
 38     friend ostream& operator<<(ostream &out,const BigInteger& x)
 39     {
 40         out << x.s.back();
 41         for(int i = x.s.size()-2;i>=0;i--)
 42         {
 43             char buf[20];
 44             sprintf(buf,"%8d",x.s[i]);
 45             for(int j = 0;j<strlen(buf);j++)
 46             {
 47                 out << buf[j];
 48             }
 49         }
 50         return out;
 51     }
 52     friend istream& operator>>(istream &in,BigInteger& x)
 53     {
 54         string s;
 55         if(!(in >> s)) return in;
 56         x = s;
 57         return in;
 58     }
 59 
 60     bool operator<(const BigInteger& b) const
 61     {
 62         if(s.size()!=b.s.size())
 63         {
 64             return s.size()<b.s.size();
 65         }
 66         for(int i = s.size()-1;i>=0;i--)
 67         {
 68             if(s[i]!=b.s[i])
 69             {
 70                 return s[i]<b.s[i];
 71             }
 72         }
 73         return false;
 74     }
 75     bool operator>(const BigInteger& b) const
 76     {
 77         return b<*this;
 78     }
 79     bool operator<=(const BigInteger& b) const
 80     {
 81         return !(b<*this);
 82     }
 83     bool operator>=(const BigInteger& b) const
 84     {
 85         return !(*this<b);
 86     }
 87     bool operator!=(const BigInteger& b) const
 88     {
 89         return (b< *this||*this<b);
 90     }
 91     bool operator==(const BigInteger& b) const
 92     {
 93         return !(b<*this)&&!(*this<b);
 94     }
 95     BigInteger operator+(const BigInteger& b) const
 96     {
 97         BigInteger c;
 98         c.s.clear();
 99         for(int i = 0,g = 0;;i++)
100         {
101             if(g==0&&i>=s.size()&&i>=b.s.size())//當進位爲零而且加完了,退出。若是加完了進位不爲零,就繼續把進位補上,在退出
102             {
103                 break;
104             }
105             int x = g;//g爲進位數,滿一個BASE才向下進一位
106             if(i<s.size()) x+=s[i];
107             if(i<b.s.size()) x+=b.s[i];
108             c.s.push_back(x%BASE);//進位後本位上的數
109             g = x/BASE;//更新進位數
110         }
111         return c;
112     }
113     BigInteger operator+=(const BigInteger& b)
114     {
115         *this = *this+b;
116         return *this;
117     }
118 };
119 set<BigInteger> s;
120 map<BigInteger, int> m;
121 int main()
122 {
123     BigInteger y;
124     BigInteger x = y;
125     BigInteger z = 123;
126 
127     BigInteger a, b;
128     cin >> a >> b;
129     cout << a + b << "\n";
130     cout << BigInteger::BASE << "\n";
131     return 0;
132 }
View Code

 

參考代碼:https://github.com/aoapc-book/aoapc-bac2nd/blob/master/ch5/BigInteger.cpp

參考文章:

關於sscanf,sprintf的使用:

https://www.runoob.com/cprogramming/c-function-sscanf.html

https://www.runoob.com/cprogramming/c-function-sprintf.html

相關文章
相關標籤/搜索