大数运算教程 c++
由于c++的内置整型一般最大为long long,只能保存2^63次方的整数,在很多时候需求量较大时可能会发生溢出等现象
所以大数类便应运而生
1 class bigNum{ 4 private: 5 int a[maxn],len; 6 char sign;
7 };
在此分享一下大数算法
大数加法:
通过我们从小到大进行的各种加法运算,发现列竖式这样的方法十分符合计算机执行力强大的特征,而且又较好实现,废话8说,看图
因此,只需要将对应位相加,如果有进位的话,可置一个flag,用于表达是否进位
为了方便运算,可以先用string存储数据,然后将之倒过来放进int 数组里。
这是大数类的构造函数和赋值函数
1 bigNum():len(0){memset(a,0,sizeof(a));}; 2 bigNum(string s){change(s);}; 3 bigNum(int n){change(to_string(n));}; 4 void change(string s) 5 { 6 if(s[0]=='-'){ 7 sign='-'; 8 s.erase(s.begin()); 9 } 10 else sign='+'; 11 len=s.size(); 12 for(int i=len-1;i>=0;--i) a[len-1-i]=s[i]-'0';//将数组颠倒,便于计算 13 }
代码如下:
1 bigNum add(const bigNum &rhs)const 2 { 3 bigNum ans;//返回的对象 4 memset(ans.a,0,sizeof(ans.a));//清零很重要,否则易出现很多错误 5 int mlen=max(this->len,rhs.len),flag=0;//flag 6 for(int i=0;i<mlen;++i){ 7 ans.a[i]=this->a[i]+rhs.a[i]+flag; 8 flag=0; 9 flag=ans.a[i]/10; 10 ans.a[i]%=10; 11 } 12 if(flag) ans.a[mlen++]=1; 13 ans.len=mlen; 14 return ans; 15 }
同理,对于减法,也是用列竖式的方法
代码如下:
1 bigNum sub(const bigNum &rhs)const 2 { 3 bigNum ans; 4 memset(ans.a,0,sizeof(ans.a)); 5 int mlen=this->len; 6 for(int i=0;i<mlen;++i){ 7 ans.a[i]+=this->a[i]-rhs.a[i]; 8 if(ans.a[i]<0){ 9 ans.a[i]+=10; 10 ans.a[i+1]-=1;//我们默认当前值大于后一个值,那么我们只需要无脑借位就好,借成-1也无所谓,最后效果是一样的 11 } 12 } 13 while(!ans.a[mlen]&&mlen>0) --mlen;//用于清除前导0 14 ans.len=mlen+1; 15 return ans; 16 }
对于大数乘法,就要稍微复杂一点了,不过原理依然是一样的,也是列竖式计算
观察图
不难发现这一块便是一个大数加法,如果位数多了也是反复进行加法,控制好下标便很简单,建议拿纸对着代码模拟一遍
1 bigNum mul(const bigNum &rhs)const 2 { 3 bigNum ans; 4 memset(ans.a,0,sizeof(ans.a)); 5 int mlen=this->len+rhs.len; 6 for(int i=0;i<this->len;++i){ 7 for(int j=0;j<rhs.len;++j){ 8 ans.a[j+i]+=this->a[i]*rhs.a[j]; 9 ans.a[j+i+1]+=ans.a[j+i]/10; 10 ans.a[j+i]%=10; 11 } 12 } 13 while(!ans.a[mlen]&&mlen>0) --mlen;//与前面一样,依然是去除前导零 14 ans.len=mlen+1; 15 return ans; 16 }
最后到了大数除法,由于高精除高精码量太多,而且很复杂,在此给出高精除低精的代码,看了代码在进行解释
(依然是列竖式进行计算)
1 bigNum operator/(const int &rhs)const 2 { 3 bigNum ans; 4 string s; 5 int num=0; 6 for(int i=len-1;i>=0;--i){ 7 s.push_back((num*10+a[i])/rhs+48); 8 num=(num*10+a[i])%rhs; 9 } 10 for(int i=0;s[0]==48;++i) s.erase(s.begin());//去除所有前导0 11 if(s.empty()) ans=0;//特判s是否为空,如果为空则输出个0(不然爆0) 12 else ans=s; 13 return ans; 14 }
6,7,8行为关键部分,我们从高位开始进行不断除-取余的运算,将余数取到次高位进行储存,这样不断往复,得到的便是除数,而最后剩下的num则为余数
最后奉上重载得差不多的大数类,可以进行大部分整数运算
1 #include <iostream> 2 #include <cstring> 3 #include <string> 4 #include <algorithm> 5 using namespace std; 6 const int maxn=10005; 7 class bigNum{ 8 friend istream &operator>>(istream &in,bigNum &n); 9 friend ostream &operator<<(istream &out,const bigNum &n);//此处const很关键,决定了能否直接输出非左值 10 private: 11 int a[maxn],len; 12 char sign; 13 public: 14 bigNum():len(0){memset(a,0,sizeof(a));}; 15 bigNum(string s){change(s);}; 16 bigNum(int n){change(to_string(n));}; 17 void change(string s) 18 { 19 if(s[0]=='-'){ 20 sign='-'; 21 s.erase(s.begin()); 22 } 23 else sign='+'; 24 len=s.size(); 25 for(int i=len-1;i>=0;--i) a[len-1-i]=s[i]-'0'; 26 } 27 void print()const 28 { 29 if(sign=='-') cout<<this->sign; 30 for(int i=len-1;i>=0;--i) cout<<this->a[i]; 31 } 32 bigNum add(const bigNum &rhs)const 33 { 34 bigNum ans;//ÓÃÓÚ·µ»ØµÄans¶ÔÏó 35 memset(ans.a,0,sizeof(ans.a)); 36 int mlen=max(this->len,rhs.len),flag=0; 37 for(int i=0;i<mlen;++i){ 38 ans.a[i]=this->a[i]+rhs.a[i]+flag; 39 flag=0; 40 flag=ans.a[i]/10; 41 ans.a[i]%=10; 42 } 43 if(flag) ans.a[mlen++]=1; 44 ans.len=mlen; 45 return ans; 46 } 47 bigNum sub(const bigNum &rhs)const 48 { 49 bigNum ans; 50 memset(ans.a,0,sizeof(ans.a)); 51 int mlen=this->len; 52 for(int i=0;i<mlen;++i){ 53 ans.a[i]+=this->a[i]-rhs.a[i]; 54 if(ans.a[i]<0){ 55 ans.a[i]+=10; 56 ans.a[i+1]-=1; 57 } 58 } 59 while(!ans.a[mlen]&&mlen>0) --mlen; 60 ans.len=mlen+1; 61 return ans; 62 } 63 bigNum mul(const bigNum &rhs)const 64 { 65 bigNum ans; 66 memset(ans.a,0,sizeof(ans.a)); 67 int mlen=this->len+rhs.len; 68 for(int i=0;i<this->len;++i){ 69 for(int j=0;j<rhs.len;++j){ 70 ans.a[j+i]+=this->a[i]*rhs.a[j]; 71 ans.a[j+i+1]+=ans.a[j+i]/10; 72 ans.a[j+i]%=10; 73 } 74 } 75 while(!ans.a[mlen]&&mlen>0) --mlen; 76 ans.len=mlen+1; 77 return ans; 78 } 79 public: 80 bigNum operator+(const bigNum &rhs)const 81 { 82 return this->add(rhs); 83 } 84 bigNum operator-(const bigNum &rhs)const 85 { 86 if(*this<rhs){ 87 bigNum ans=rhs.sub(*this); 88 ans.sign='-'; 89 return ans; 90 } 91 else return this->sub(rhs); 92 } 93 bigNum operator*(const bigNum &rhs)const 94 { 95 return this->mul(rhs); 96 } 97 bigNum operator*(const int &rhs)const 98 { 99 return this->mul(to_string(rhs)); 100 } 101 bigNum &operator+=(const bigNum &rhs) 102 { 103 *this=*this+rhs; 104 return *this; 105 } 106 bigNum &operator-=(const bigNum &rhs) 107 { 108 *this=*this-rhs; 109 return *this; 110 } 111 bigNum operator/(const int &rhs)const 112 { 113 bigNum ans; 114 string s; 115 int num=0; 116 for(int i=len-1;i>=0;--i){ 117 s.push_back((num*10+a[i])/rhs+48); 118 num=(num*10+a[i])%rhs; 119 } 120 for(int i=0;s[0]==48;++i) s.erase(s.begin()); 121 if(s.empty()) ans=0; 122 else ans=s; 123 return ans; 124 } 125 bigNum operator%(const int &rhs)const 126 { 127 bigNum ans; 128 string s; 129 int num=0; 130 for(int i=len-1;i>=0;--i){ 131 s.push_back((num*10+a[i])/rhs+48); 132 num=(num*10+a[i])%rhs; 133 } 134 return num; 135 } 136 bool operator<(const bigNum &rhs)const 137 { 138 if(this->len<rhs.len) return 1; 139 else if(this->len>rhs.len) return 0; 140 else{ 141 int flag=0; 142 for(int i=this->len-1;i>=0;--i){ 143 if(this->a[i]>rhs.a[i]){ 144 flag=0; 145 break; 146 } 147 if(this->a[i]<rhs.a[i]){ 148 flag=1; 149 break; 150 } 151 } 152 return flag; 153 } 154 } 155 bool operator>(const bigNum &rhs)const 156 { 157 if(this->len>rhs.len) return 1; 158 else if(this->len<rhs.len) return 0; 159 else{ 160 int flag=0; 161 for(int i=this->len-1;i>=0;--i){ 162 if(this->a[i]<rhs.a[i]){ 163 flag=0; 164 break; 165 } 166 if(this->a[i]>rhs.a[i]){ 167 flag=1; 168 break; 169 } 170 } 171 return flag; 172 } 173 } 174 bool operator==(const bigNum &rhs) const 175 { 176 int flag=0; 177 if(this->len==rhs.len){ 178 flag=1; 179 for(int i=0;i<this->len;++i){ 180 if(this->a[i]!=rhs.a[i]){ 181 flag=0; 182 break; 183 } 184 } 185 } 186 return flag; 187 } 188 }; 189 istream &operator>>(istream &in,bigNum &n) 190 { 191 string s; 192 in>>s; 193 n.change(s); 194 return in; 195 } 196 ostream &operator<<(ostream &out,const bigNum &n) 197 { 198 n.print(); 199 return out; 200 } 201 int main() 202 { 203 int b; 204 bigNum a,c; 205 cin>>a>>c>>b; 206 cout<<a%b<<endl; 207 cout<<a*c<<endl; 208 cout<<a+c<<endl; 209 cout<<a-c<<endl; 210 cout<<a/b<<endl; 211 return 0; 212 }