码迷,mamicode.com
首页 > 其他好文 > 详细

大数模板

时间:2015-11-07 06:18:17      阅读:252      评论:0      收藏:0      [点我收藏+]

标签:

  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<conio.h>
  4 #include<stdlib.h>
  5 #include<time.h>
  6 #define N 10000
  7 // 大数模板。。。
  8 class BigNum
  9 {
 10   public:
 11     int s[N];  //存放各位数字,s[0]为符号位,1代表正数,-1代表负数
 12                //数组内高位存高位,123存在里面则为 1 3 2 1 ,第1个 1表示符号
 13     int len;   //长度
 14   public:
 15     BigNum()
 16     {
 17       memset(s,0,sizeof(s));  //初始化全0
 18       s[0]=1;                 //默认正数
 19       len=2;                  //变量初始化为0
 20     }
 21     void Display()            //输出
 22     {
 23       if(s[0]==-1) printf("-");
 24       for(int i=len-1;i>0;i--)
 25         printf("%d",s[i]);
 26     }
 27     void Sets(char *ts)        //赋值(bug 中途不能赋值)
 28     {
 29       int lts=strlen(ts);      //应对输入直接是 Sets("123");的情况,重新申请空间
 30       char *t;
 31       t=(char *)malloc(sizeof(char)*(lts+1));
 32       strcpy(t,ts);            //承接ts字符串
 33       Clear();
 34       int lt=strlen(t);       //获取字符串长度
 35       int flag=1;             //如果字符串带负号,flag为1,否则为0
 36       if(t[0]==-) s[0]=-1;  //设置符号位
 37       else
 38       {
 39         s[0]=1;
 40         flag=0;
 41       }
 42       int j=0;                //字符串高位消0
 43       for(int i=flag;i<lt-1;i++)
 44         if(t[i]==0) j++;
 45         else break;
 46       for(int i=j+flag;i<=lt;i++)
 47       {
 48         t[i-j]=t[i];
 49       }
 50       lt=lt-j;
 51       for(int i=lt;i>flag;i--)//如果字符串带负号,那么t[0]要被忽略
 52       {
 53         s[lt-i+1]=t[i-1]-0;
 54       }
 55       len=lt+!flag;           //如果字符串不带负号,那么len=lt+1
 56       free(t);
 57     }
 58     void Clear()
 59     {
 60       memset(s,0,sizeof(s));  //初始化全0
 61       s[0]=1;                 //默认正数
 62       len=2;                  //变量初始化为0
 63     }
 64     BigNum Nizhi()            //除法中用到,排除符号位颠倒数组
 65     {
 66       BigNum ans;
 67       ans.s[0]=s[0];
 68       for(int i=1;i<=len/2;i++)
 69       {
 70         ans.s[i]=s[len-i];
 71         ans.s[len-i]=s[i];
 72       }
 73       ans.len=len;
 74       return ans;
 75     }
 76     friend bool operator<(const BigNum &a,const BigNum &b);
 77     friend bool operator>(const BigNum &a,const BigNum &b);
 78     friend bool operator<=(const BigNum &a,const BigNum &b);
 79     friend bool operator>=(const BigNum &a,const BigNum &b);
 80     friend BigNum operator+(BigNum a,BigNum b);
 81     friend void operator+=(BigNum &a,BigNum b);
 82     friend BigNum operator-(BigNum a,BigNum b);
 83     friend void operator-=(BigNum &a,BigNum b);
 84     friend BigNum operator*(BigNum a,BigNum b);
 85     friend void operator*=(BigNum &a,BigNum b);
 86     friend BigNum operator/(BigNum a,BigNum b);
 87     friend void operator/=(BigNum &a,BigNum b);
 88     friend bool operator==(const BigNum &a,const BigNum &b);
 89 };
 90 bool operator<(const BigNum &a,const BigNum &b)
 91 {
 92   bool flag;
 93   if(a.s[0]==-1&&b.s[0]==1) return 1;      //如果a为负,b为正,那么a<b
 94   else if(a.s[0]==1&&b.s[0]==-1) return 0; //如果a为正,b为负,那么a>b
 95   else if(a.s[0]==1&&b.s[0]==1) flag=1;    //如果a、b都为正,flag=1,表示a、b大小和符号无关
 96   else flag=0;                             //如果a、b都为负,flag=0,表示a、b大小和符号有关
 97   // flag=1 时,a、b大小和除符号外的数字大小成正比,反之反比
 98   if(a.len>b.len) return !flag; //a的位数多,所以a大,返回0
 99   else if(a.len<b.len) return flag; //a的位数少,所以a小,返回1
100   else
101   {
102     int i=a.len;                    //从最高位开始比
103     while(i-->1)
104     {
105       if(a.s[i]>b.s[i]) return !flag;
106       else if(a.s[i]<b.s[i]) return flag;
107     }
108     return 0;                       //没有差异即相等返回0
109   }
110 }
111 bool operator<=(const BigNum &a,const BigNum &b) //同 <
112 {
113   bool flag; // flag=1 表示两者都是正的 =0表示两者都是负的
114   if(a.s[0]==-1&&b.s[0]==1) return 1;
115   else if(a.s[0]==1&&b.s[0]==-1) return 0;
116   else if(a.s[0]==1&&b.s[0]==1) flag=1;
117   else flag=0;
118   // flag 表示1 ,!flag 表示0
119   if(a.len>b.len) return !flag;
120   else if(a.len<b.len) return flag;
121   else
122   {
123     int i=a.len;
124     while(i-->1)
125     {
126       if(a.s[i]>b.s[i]) return !flag;
127       else if(a.s[i]<b.s[i]) return flag;
128     }
129     return 1;
130   }
131 }
132 bool operator>(const BigNum &a,const BigNum &b)
133 {
134   return !(a<=b);
135 }
136 bool operator>=(const BigNum &a,const BigNum &b)
137 {
138   return !(a<b);
139 }
140 bool operator==(const BigNum &a,const BigNum &b)
141 {
142   if(a.s[0]==-1&&b.s[0]==1) return 0;
143   else if(a.s[0]==1&&b.s[0]==-1) return 0;
144   if(a.len>b.len) return 0;
145   else if(a.len<b.len) return 0;
146   else
147   {
148     int i=a.len;
149     while(i-->1)
150     {
151       if(a.s[i]>b.s[i]) return 0;
152       else if(a.s[i]<b.s[i]) return 0;
153     }
154     return 1;
155   }
156 }
157 BigNum operator-(BigNum a,BigNum b)
158 {
159   BigNum ans;
160   if(a.s[0]==1&&b.s[0]==-1)      //如果a正,b负,那么等同于a+|b|
161   {
162     b.s[0]=1;
163     return a+b;
164   }
165   else if(a.s[0]==-1&&b.s[0]==1) //如果a负,b正,那么等同于-(|a|+b)
166   {
167     a.s[0]=1;
168     ans=a+b;
169     ans.s[0]=-1;
170     return ans;
171   }
172   else if(a.s[0]==-1&&b.s[0]==-1) //如果a负,b负,那么等同于|b|-|a|
173   {
174     a.s[0]=1;
175     b.s[0]=1;
176     return b-a;
177   }
178   else             //进到这一区域的,a为正,b为正
179   {
180     if(a<b)        //如果a<b,那么等同于-(b-a)
181     {
182       ans=b-a;
183       ans.s[0]=-1;
184     }
185     else           //进到这一区域a、b为正,且a>b,也就是说减出来的绝对是正数
186     {
187       int i=0;
188       int lm=a.len>b.len?a.len:b.len;  //由于减出来必定是正数,不需要考虑lm-1位<0的情况
189       for(int i=1;i<lm;i++)
190       {
191         int tmp=ans.s[i]+a.s[i]-b.s[i];
192         if(tmp<0)
193         {
194           ans.s[i+1]--;
195           tmp+=10;
196         }
197         ans.s[i]=tmp;
198       }
199       while(lm>2)    //清楚高位0,最多清楚到0为止
200       {
201         if(ans.s[lm-1]==0) lm--;
202         else break;
203       }
204       ans.len=lm;
205     }
206   }
207   return ans;
208 }
209 void operator-=(BigNum &a,BigNum b)
210 {
211   a=a-b;
212 }
213 BigNum operator+(BigNum a,BigNum b)
214 {
215   BigNum ans;
216   int lm=a.len>b.len?a.len:b.len;
217   if(a.s[0]*b.s[0]==1)   //如果两者符号位相同
218   {
219     ans.s[0]=a.s[0];     //结果符号位与任意一个相同
220     for(int i=1;i<lm;i++)
221     {
222       int tmp=ans.s[i]+a.s[i]+b.s[i];
223       if(tmp>=10)
224       {
225         ans.s[i+1]++;
226       }
227       ans.s[i]=tmp%10;
228     }
229     if(ans.s[lm]==0) ans.len=lm; //如果最高位没有进位,那么长度不变,否则加1
230     else ans.len=lm+1;
231   }
232   else                           //如果a、b符号不同,可以转化为减法
233   {
234     if(a.s[0]==1)
235     {
236       b.s[0]=1;
237       return a-b;
238     }
239     else
240     {
241       a.s[0]=1;
242       return b-a;
243     }
244   }
245   return ans;
246 }
247 void operator+=(BigNum &a,BigNum b)
248 {
249   a=a+b;
250 }
251 
252 BigNum operator*(BigNum a,BigNum b)
253 {
254   BigNum ans;
255   ans.s[0]=a.s[0]*b.s[0];           //乘法和除法的符号位简单处理
256   for(int i=1;i<a.len;i++)
257   {
258     for(int j=1;j<b.len;j++)
259     {
260       ans.s[i+j-1]+=a.s[i]*b.s[j];  //先存
261     }
262   }
263   int maxt=a.len+b.len;             //最多位数
264   for(int i=1;i<maxt;i++)           //处理每个位上的数
265   {
266     if(ans.s[i]>=10)
267     {
268       ans.s[i+1]+=ans.s[i]/10;
269       ans.s[i]=ans.s[i]%10;
270     }
271   }
272   int i;
273   for(i=maxt;i>1;i--)               //处理高位0
274   {
275     if(ans.s[i]!=0) break;
276   }
277   ans.len=i+1;
278   return ans;
279 }
280 void operator*=(BigNum &a,BigNum b)
281 {
282   a=a*b;
283 }
284 BigNum operator/(BigNum a,BigNum b)
285 {
286   /*
287     思路: 首先从a的高位往低位数,如果还<b,那么就再加1位,知道>=b,然后遍历1-9,判断此时
288         合适取值,和平常手动计算思路一样
289   */
290   BigNum ans;
291   ans.s[0]=a.s[0]*b.s[0];
292   b.s[0]=1;       //中途比较需要
293   BigNum tmp;     //添位取值
294   tmp.len=1;      //刚开始为无值,就是说连a的最高位都还没纳入
295   BigNum zj;      //中间变量,比较时需要,由于数组是倒置的,所以加这一变量
296   ans.len=1;      //答案还是空的
297   int j=a.len;    //j固定指向a,不断取值
298   bool match=1;   //match为0退出循环
299   while(1)
300   {
301     while(1)   //如果还没取够值,就继续加位
302     {
303       if(j==1)    //如果a到了符号位,那么可以退出循环了
304       {
305         match=0;
306         break;
307       }
308       tmp.s[tmp.len++]=a.s[--j]; //加位,由于开始不好确定位数,所以直接正向不好办
309       zj=tmp.Nizhi();            //数组颠倒后再去比较
310       if(b<=zj) break;           //如果b<=zj了,就可以退出了,否则该位为0
311       ans.s[ans.len++]=0;
312     }
313     if(!match) break;            //match为0退出循环
314     int i;
315     BigNum r=b;                  //r为最大容许的乘后值
316     for(i=2;i<=10;i++)
317     {
318       BigNum p;
319       p.s[p.len-1]=i;    //获得 2 - 10 . 赋值过程不符常规,但由于下一步是乘,可以忽略该bug
320       BigNum u=b*p;      //如果u超过了中间变量,可以退出了,同i应该减1
321       if(zj<u) break;
322       r=u;               //乘得的最大数
323     }
324     i--;
325     ans.s[ans.len++]=i;          //逐位求值
326     zj=zj-r;                     //获得余数
327     BigNum q;
328     if(zj==q) zj.len--;          //如果余数为0,那么去掉,不能出现00,不然会出错
329     tmp=zj.Nizhi();              //重新逆置
330   }
331   ans=ans.Nizhi();               //逆置获得答案
332   while(ans.s[ans.len-1]==0&&ans.len>2) //高位消0
333   {
334     ans.len--;
335   }
336   return ans;
337 }
338 void operator/=(BigNum &a,BigNum b)
339 {
340   a=a/b;
341 }
342 int main()
343 {
344 
345   return 0;
346 }

 

大数模板

标签:

原文地址:http://www.cnblogs.com/hchlqlz-oj-mrj/p/4944075.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!