c++大整数类的几种实现方法与解析

来源:互联网 发布:金十数据现货原油 编辑:程序博客网 时间:2024/05/16 19:52

在oj上做题时,相信大家遇到过很多要求大整数的题目,这时候,我们就需要用到所谓的高精度算法,即用数组来储存整数,模拟四则运算以及其他常见的运算,下面就让我们来分析一下几种实现大整数的方法


一.用vector来储存大整数

[cpp] view plain copy
  1. <span style="font-size:24px;color:#FF0000;"><strong><span style="font-size:14px;color:#000000;">#include<iostream>  
  2. #include<vector>  
  3. #include<stack>  
  4. #include<cstring>  
  5. #include<string>  
  6. #include<cstdio>  
  7. using namespace std;  
  8. class BigInteger    
  9. {  
  10. public:  
  11.     static const int base=100000000;  
  12.     static const int width=8;  
  13.     vector<int>s;  
  14.     BigInteger(long long num=0){*this=num;}    //构造函数  
  15.     BigInteger operator=(long long num)  
  16.     {  
  17.         s.clear();  
  18.         do{  
  19.             s.push_back(num%base);  
  20.             num=num/base;  
  21.         }while(num>0);  
  22.         return *this;  
  23.     }  
  24.     BigInteger operator=(const string &str)      //重载=号  
  25.     {  
  26.         s.clear();  
  27.         int x,len=(str.length()-1)/width+1;  
  28.         for(int i=0;i<len;i++){  
  29.             int end=str.length()-i*width;  
  30.             int start=max(0,end-width);  
  31.             sscanf(str.substr(start,end-start).c_str(),"%d",&x);    //格式符%d是读入十进制整数  
  32.                                                                 //string.c_str是Borland封装的String类中的一个函数,它返回当前字符串的首字符地址  
  33.             s.push_back(x);  
  34.         }  
  35.         return *this;  
  36.     }  
  37.     friend ostream & operator<<(ostream &out,const BigInteger& x)   //重载输出号  
  38.     {  
  39.     out<<x.s.back();  
  40.     for(int i=x.s.size()-2;i>=0;i--){  
  41.         char buf[20];  
  42.         sprintf(buf,"%08d",x.s[i]);  
  43.         for(int j=0;j<int(strlen(buf));j++)  
  44.             out<<buf[j];  
  45.     }  
  46.     return out;  
  47.     }  
  48.     friend istream & operator>>(istream &in,BigInteger& x)   //重载输入号  
  49.     {  
  50.     string s;  
  51.     if(!(in>>s)) return in;  
  52.     x=s;  
  53.     return in;  
  54.     }  
  55.     BigInteger operator+(const BigInteger& b)const   //重载加号  
  56.     {  
  57.         BigInteger c;  
  58.         c.s.clear();  
  59.         for(int i=0,g=0;;i++){  
  60.             if(g==0&&i>=s.size()&&i>=b.s.size()) break;  
  61.             int x=g;  
  62.             if(i<s.size()) x+=s[i];  
  63.             if(i<b.s.size()) x+=b.s[i];  
  64.             c.s.push_back(x%base);  
  65.             g=x/base;  
  66.         }  
  67.         return c;  
  68.     }  
  69.     BigInteger operator-(const BigInteger& b)   //重载减号,默认前面大于后面  
  70.     {  
  71.         BigInteger c;  
  72.         c.s.clear();  
  73.         if(*this>b){  
  74.             int i,g;  
  75.         for(i=0,g=0;;i++){  
  76.             if(g==0&&i>=b.s.size()) break;  
  77.             int x=g;  
  78.             if(s[i]<b.s[i]){  
  79.                 s[i+1]-=1;  
  80.                 s[i]=s[i]+base;  
  81.             }  
  82.             if(i<s.size()) x+=s[i];  
  83.             if(i<b.s.size()) x-=b.s[i];  
  84.             c.s.push_back(x%base);  
  85.             g=x/base;  
  86.         }  
  87.         int x=0;  
  88.         for(;i<s.size();i++){  
  89.             x+=s[i];  
  90.             c.s.push_back(x%base);  
  91.             x=x/base;  
  92.         }  
  93.         }  
  94.         return c;  
  95.     }  
  96.     bool operator<(const BigInteger& b)const   //重载小于号  
  97.     {  
  98.         if(s.size()!=b.s.size()) return s.size()<b.s.size();  
  99.         for(int i=s.size()-1;i>=0;i--)  
  100.             if(s[i]!=b.s[i]) return s[i]<b.s[i];  
  101.         return false;  
  102.     }  
  103.     bool operator>(const BigInteger& b)const   //重载大于号  
  104.     {  
  105.         return b<*this;  
  106.     }  
  107.     bool operator<=(const BigInteger& b)const  
  108.     {  
  109.         return !(b<*this);  
  110.     }  
  111.     bool operator>=(const BigInteger& b)const  
  112.     {  
  113.         return !(*this<b);  
  114.     }  
  115.     bool operator==(const BigInteger& b)const  //重载等于号  
  116.     {  
  117.         return !(b<*this)&&!(*this<b);  
  118.     }  
  119.     BigInteger operator+=(const BigInteger& b)  
  120.     {  
  121.         *this=(*this+b);  
  122.         return *this;  
  123.     }  
  124.     BigInteger operator-=(const BigInteger& b)  
  125.     {  
  126.         *this=(*this-b);  
  127.         return *this;  
  128.     }  
  129. };</span></strong></span>  

这段代码是我参照算法竞赛入门上面的,下面我们来分析一下具体实现过程:

       首先定义了base=100000000,width=8,来实现大整数每8位用int的方式保存进vector内,然后通过重载赋值运算符,输入字符串的形式实现将字符串转换为vector容器值。

       然后是加法的重载实现,通过每取八位出来进行+运算,若结果大于8位则进一位,并将这一位保留到下一次的运算中。

       而减法的重载实现,则是通过每取八位出来进行-运算,若结果小于0则从s[i+1],也就是vector容器内后一个值中取出10000000来进行计算,而s[i+1]则减一来实现借位。


二.通过数组的方式储存大整数

[cpp] view plain copy
  1. <span style="font-size:24px;color:#FF0000;"><strong><span style="color:#000000;"><span style="font-size:14px;">#include<string>  
  2. #include<iostream>  
  3. #include<iosfwd>  
  4. #include<cmath>  
  5. #include<cstring>  
  6. #include<stdlib.h>  
  7. #include<stdio.h>  
  8. #include<cstring>  
  9. #define MAX_L 2005   
  10. using namespace std;  
  11.   
  12. class bign  
  13. {  
  14. public:  
  15.     int len, s[MAX_L];//数的长度,记录数组  
  16. //构造函数  
  17.     bign();  
  18.     bign(const char*);  
  19.     bign(int);  
  20.     bool sign;//符号 1正数 0负数  
  21.     string toStr() const;//转化为字符串,主要是便于输出  
  22.     friend istream& operator>>(istream &,bign &);//重载输入流  
  23.     friend ostream& operator<<(ostream &,bign &);//重载输出流  
  24. //重载复制  
  25.     bign operator=(const char*);  
  26.     bign operator=(int);  
  27.     bign operator=(const string);  
  28. //重载各种比较  
  29.     bool operator>(const bign &) const;  
  30.     bool operator>=(const bign &) const;  
  31.     bool operator<(const bign &) const;  
  32.     bool operator<=(const bign &) const;  
  33.     bool operator==(const bign &) const;  
  34.     bool operator!=(const bign &) const;  
  35. //重载四则运算  
  36.     bign operator+(const bign &) const;  
  37.     bign operator++();  
  38.     bign operator++(int);  
  39.     bign operator+=(const bign&);  
  40.     bign operator-(const bign &) const;  
  41.     bign operator--();  
  42.     bign operator--(int);  
  43.     bign operator-=(const bign&);  
  44.     bign operator*(const bign &)const;  
  45.     bign operator*(const int num)const;  
  46.     bign operator*=(const bign&);  
  47.     bign operator/(const bign&)const;  
  48.     bign operator/=(const bign&);  
  49. //四则运算的衍生运算  
  50.     bign operator%(const bign&)const;//取模(余数)  
  51.     bign factorial()const;//阶乘  
  52.     bign Sqrt()const;//整数开根(向下取整)  
  53.     bign pow(const bign&)const;//次方  
  54. //辅助的函数  
  55.     void clean();  
  56.     ~bign();  
  57. };  
  58. #define max(a,b) a>b ? a : b  
  59. #define min(a,b) a<b ? a : b  
  60.   
  61. bign::bign()  
  62. {  
  63.     memset(s, 0, sizeof(s));  
  64.     len = 1;  
  65.     sign = 1;  
  66. }  
  67.   
  68. bign::bign(const char *num)  
  69. {  
  70.     *this = num;  
  71. }  
  72.   
  73. bign::bign(int num)  
  74. {  
  75.     *this = num;  
  76. }  
  77.   
  78. string bign::toStr() const  
  79. {  
  80.     string res;  
  81.     res = "";  
  82.     for (int i = 0; i < len; i++)  
  83.         res = (char)(s[i] + '0') + res;  
  84.     if (res == "")  
  85.         res = "0";  
  86.     if (!sign&&res != "0")  
  87.         res = "-" + res;  
  88.     return res;  
  89. }  
  90.   
  91. istream &operator>>(istream &in, bign &num)  
  92. {  
  93.     string str;  
  94.     in>>str;  
  95.     num=str;  
  96.     return in;  
  97. }  
  98.   
  99. ostream &operator<<(ostream &out, bign &num)  
  100. {  
  101.     out<<num.toStr();  
  102.     return out;  
  103. }  
  104.   
  105. bign bign::operator=(const char *num)  
  106. {  
  107.     memset(s, 0, sizeof(s));  
  108.     char a[MAX_L] = "";  
  109.     if (num[0] != '-')  
  110.         strcpy(a, num);  
  111.     else  
  112.         for (int i = 1; i < strlen(num); i++)  
  113.             a[i - 1] = num[i];  
  114.     sign = !(num[0] == '-');  
  115.     len = strlen(a);  
  116.     for (int i = 0; i < strlen(a); i++)  
  117.         s[i] = a[len - i - 1] - 48;  
  118.     return *this;  
  119. }  
  120.   
  121. bign bign::operator=(int num)  
  122. {  
  123.     if (num < 0)  
  124.         sign = 0, num = -num;  
  125.     else  
  126.         sign = 1;  
  127.     char temp[MAX_L];  
  128.     sprintf(temp, "%d", num);  
  129.     *this = temp;  
  130.     return *this;  
  131. }  
  132.   
  133. bign bign::operator=(const string num)  
  134. {  
  135.     const char *tmp;  
  136.     tmp = num.c_str();  
  137.     *this = tmp;  
  138.     return *this;  
  139. }  
  140.   
  141. bool bign::operator<(const bign &num) const  
  142. {  
  143.     if (sign^num.sign)  
  144.         return num.sign;  
  145.     if (len != num.len)  
  146.         return len < num.len;  
  147.     for (int i = len - 1; i >= 0; i--)  
  148.         if (s[i] != num.s[i])  
  149.             return sign ? (s[i] < num.s[i]) : (!(s[i] < num.s[i]));  
  150.     return !sign;  
  151. }  
  152.   
  153. bool bign::operator>(const bign&num)const  
  154. {  
  155.     return num < *this;  
  156. }  
  157.   
  158. bool bign::operator<=(const bign&num)const  
  159. {  
  160.     return !(*this>num);  
  161. }  
  162.   
  163. bool bign::operator>=(const bign&num)const  
  164. {  
  165.     return !(*this<num);  
  166. }  
  167.   
  168. bool bign::operator!=(const bign&num)const  
  169. {  
  170.     return *this > num || *this < num;  
  171. }  
  172.   
  173. bool bign::operator==(const bign&num)const  
  174. {  
  175.     return !(num != *this);  
  176. }  
  177.   
  178. bign bign::operator+(const bign &num) const  
  179. {  
  180.     if (sign^num.sign)  
  181.     {  
  182.         bign tmp = sign ? num : *this;  
  183.         tmp.sign = 1;  
  184.         return sign ? *this - tmp : num - tmp;  
  185.     }  
  186.     bign result;  
  187.     result.len = 0;  
  188.     int temp = 0;  
  189.     for (int i = 0; temp || i < (max(len, num.len)); i++)  
  190.     {  
  191.         int t = s[i] + num.s[i] + temp;  
  192.         result.s[result.len++] = t % 10;  
  193.         temp = t / 10;  
  194.     }  
  195.     result.sign = sign;  
  196.     return result;  
  197. }  
  198.   
  199. bign bign::operator++()  
  200. {  
  201.     *this = *this + 1;  
  202.     return *this;  
  203. }  
  204.   
  205. bign bign::operator++(int)  
  206. {  
  207.     bign old = *this;  
  208.     ++(*this);  
  209.     return old;  
  210. }  
  211.   
  212. bign bign::operator+=(const bign &num)  
  213. {  
  214.     *this = *this + num;  
  215.     return *this;  
  216. }  
  217.   
  218. bign bign::operator-(const bign &num) const  
  219. {  
  220.     bign b=num,a=*this;  
  221.     if (!num.sign && !sign)  
  222.     {  
  223.         b.sign=1;  
  224.         a.sign=1;  
  225.         return b-a;  
  226.     }  
  227.     if (!b.sign)  
  228.     {  
  229.         b.sign=1;  
  230.         return a+b;  
  231.     }  
  232.     if (!a.sign)  
  233.     {  
  234.         a.sign=1;  
  235.         b=bign(0)-(a+b);  
  236.         return b;  
  237.     }  
  238.     if (a<b)  
  239.     {  
  240.         bign c=(b-a);  
  241.         c.sign=false;  
  242.         return c;  
  243.     }  
  244.     bign result;  
  245.     result.len = 0;  
  246.     for (int i = 0, g = 0; i < a.len; i++)  
  247.     {  
  248.         int x = a.s[i] - g;  
  249.         if (i < b.len) x -= b.s[i];  
  250.         if (x >= 0) g = 0;  
  251.         else  
  252.         {  
  253.             g = 1;  
  254.             x += 10;  
  255.         }  
  256.         result.s[result.len++] = x;  
  257.     }  
  258.     result.clean();  
  259.     return result;  
  260. }  
  261.   
  262. bign bign::operator * (const bign &num)const  
  263. {  
  264.     bign result;  
  265.     result.len = len + num.len;  
  266.   
  267.     for (int i = 0; i < len; i++)  
  268.         for (int j = 0; j < num.len; j++)  
  269.             result.s[i + j] += s[i] * num.s[j];  
  270.   
  271.     for (int i = 0; i < result.len; i++)  
  272.     {  
  273.         result.s[i + 1] += result.s[i] / 10;  
  274.         result.s[i] %= 10;  
  275.     }  
  276.     result.clean();  
  277.     result.sign = !(sign^num.sign);  
  278.     return result;  
  279. }  
  280.   
  281. bign bign::operator*(const int num)const  
  282. {  
  283.     bign x = num;  
  284.     bign z = *this;  
  285.     return x*z;  
  286. }  
  287. bign bign::operator*=(const bign&num)  
  288. {  
  289.     *this = *this * num;  
  290.     return *this;  
  291. }  
  292.   
  293. bign bign::operator /(const bign&num)const  
  294. {  
  295.     bign ans;  
  296.     ans.len = len - num.len + 1;  
  297.     if (ans.len < 0)  
  298.     {  
  299.         ans.len = 1;  
  300.         return ans;  
  301.     }  
  302.   
  303.     bign divisor = *this, divid = num;  
  304.     divisor.sign = divid.sign = 1;  
  305.     int k = ans.len - 1;  
  306.     int j = len - 1;  
  307.     while (k >= 0)  
  308.     {  
  309.         while (divisor.s[j] == 0) j--;  
  310.         if (k > j) k = j;  
  311.         char z[MAX_L];  
  312.         memset(z, 0, sizeof(z));  
  313.         for (int i = j; i >= k; i--)  
  314.             z[j - i] = divisor.s[i] + '0';  
  315.         bign dividend = z;  
  316.         if (dividend < divid) { k--; continue; }  
  317.         int key = 0;  
  318.         while (divid*key <= dividend) key++;  
  319.         key--;  
  320.         ans.s[k] = key;  
  321.         bign temp = divid*key;  
  322.         for (int i = 0; i < k; i++)  
  323.             temp = temp * 10;  
  324.         divisor = divisor - temp;  
  325.         k--;  
  326.     }  
  327.     ans.clean();  
  328.     ans.sign = !(sign^num.sign);  
  329.     return ans;  
  330. }  
  331.   
  332. bign bign::operator/=(const bign&num)  
  333. {  
  334.     *this = *this / num;  
  335.     return *this;  
  336. }  
  337.   
  338. bign bign::operator%(const bign& num)const  
  339. {  
  340.     bign a = *this, b = num;  
  341.     a.sign = b.sign = 1;  
  342.     bign result, temp = a / b*b;  
  343.     result = a - temp;  
  344.     result.sign = sign;  
  345.     return result;  
  346. }  
  347.   
  348. bign bign::pow(const bign& num)const  
  349. {  
  350.     bign result = 1;  
  351.     for (bign i = 0; i < num; i++)  
  352.         result = result*(*this);  
  353.     return result;  
  354. }  
  355.   
  356. bign bign::factorial()const  
  357. {  
  358.     bign result = 1;  
  359.     for (bign i = 1; i <= *this; i++)  
  360.         result *= i;  
  361.     return result;  
  362. }  
  363.   
  364. void bign::clean()  
  365. {  
  366.     if (len == 0) len++;  
  367.     while (len > 1 && s[len - 1] == '\0')  
  368.         len--;  
  369. }  
  370.   
  371. bign bign::Sqrt()const  
  372. {  
  373.     if(*this<0)return -1;  
  374.     if(*this<=1)return *this;  
  375.     bign l=0,r=*this,mid;  
  376.     while(r-l>1)  
  377.     {  
  378.         mid=(l+r)/2;  
  379.         if(mid*mid>*this)  
  380.             r=mid;  
  381.         else   
  382.             l=mid;  
  383.     }  
  384.     return l;  
  385. }  
  386.   
  387. bign::~bign()  
  388. {  
  389. }</span></span></strong></span>  

这是通过数组来储存大整数,数组的每一个空间储存一个数字,来达到保存大整数的目的。

大整数加减法的实现跟前面的基本一样,也是通过模拟进位,借位的方法来实现。


下面来说一下乘法的实现过程,乘法的实现,是通过模拟手算的方法,第一个数的每一位,乘以第二个数的每一位,最后通过汇总,把结果算出来。

而除法则是四则运算中最复杂的一个,基本思路是一个一个减,看最多能减去多少个除数,但显然这样做的话效率简直是极其得低。如何使它减得更快呢?以 7546 除以 23 为例来看一下:开始商为 0。先减
去 23 的 100 倍,就是 2300,发现够减 3 次,余下 646。于是商的值就增加 300。然后用 646
减去 230,发现够减 2 次,余下 186,于是商的值增加 20。最后用 186 减去 23,够减 8 次,
因此最终商就是 328。

而上面正是用到了这种思路。

1 0
原创粉丝点击