L老师讲解的大数问题 - 2013.5.20

模板来自吉林大学acm模板及网络。

老师均添加了一些注释及改进。

第一个,普通的大数运算:

  1 #include <stdio.h>

  2 #include <string.h>

  3 /*==================================================*\

  4 | 普通的大数运算

  5 \*==================================================*/

  6 const int MAXSIZE = 200;

  7 void Add(char *str1, char *str2, char *str3);

  8 //str3: 和

  9 void Minus(char *str1, char *str2, char *str3);

 10 //要求 str1表示的数比str2的大

 11 void Mul(char *str1, char *str2, char *str3);

 12 //str3: 乘积

 13 void Div(char *str1, char *str2, char *str3, char *str4);

 14 //str3:商  str4:余数

 15 //增加str4, by lyh:13/5/19

 16 int main(void)

 17 {

 18     char str1[MAXSIZE], str2[MAXSIZE], str3[MAXSIZE], str4[MAXSIZE];

 19     while( scanf("%s %s", str1, str2) == 2 )

 20     {

 21         if( strcmp(str1, "0") )

 22         {

 23             memset(str3, '0', sizeof(str3)); // !!!!!

 24             Add(str1, str2, str3);

 25             printf("Add:%s\n", str3);

 26             memset(str3, '0', sizeof(str3));

 27             Minus(str1, str2, str3);

 28             printf("Minus:%s\n", str3);

 29             memset(str3, '0', sizeof(str3));

 30             Mul(str1, str2, str3);

 31             printf("Mul:%s\n", str3);

 32             if (strcmp(str2, "0"))

 33             {//第二个数不为0

 34                 memset(str3, '0', sizeof(str3));

 35                 memset(str4, '0', sizeof(str4));

 36                 Div(str1, str2, str3,str4);

 37                 printf("Div:%s\t%s\n", str3,str4);

 38             }

 39         }

 40         else //第一个数为0的处理

 41         {

 42             if( strcmp(str2, "0") )

 43                 printf("%s\n-%s\n0\n0\t0\n", str2, str2);

 44             else //两个数都为0的处理

 45                 printf("0\n0\n0\n0\t0\n");

 46         }

 47     }

 48     return 0;

 49 }

 50 void Add(char *str1, char *str2, char *str3)

 51 {

 52     // str3 = str1 + str2;

 53     int i, j, i1, i2, tmp, carry;

 54     int len1 = strlen(str1), len2 = strlen(str2);

 55     char ch;

 56     i1 = len1-1;

 57     i2 = len2-1;

 58     j = carry = 0;

 59     for( ; i1 >= 0 && i2 >= 0; ++j, --i1, --i2 )

 60     {

 61         tmp = str1[i1]-'0'+str2[i2]-'0'+carry;

 62         carry = tmp/10;

 63         str3[j] = tmp%10+'0';

 64     }

 65     while( i1 >= 0 )

 66     {

 67         //处理剩余加数1

 68         tmp = str1[i1--]-'0'+carry;

 69         carry = tmp/10;

 70         str3[j++] = tmp%10+'0';

 71     }

 72     while( i2 >= 0 )

 73     {

 74         //处理剩余加数2

 75         tmp = str2[i2--]-'0'+carry;

 76         carry = tmp/10;

 77         str3[j++] = tmp%10+'0';

 78     }

 79     if( carry ) //最高位进位

 80         str3[j++] = carry+'0';

 81     str3[j] = '\0';

 82     for( i=0, --j; i < j; ++i, --j )

 83     {

 84         // 逆序结果

 85         ch = str3[i];

 86         str3[i] = str3[j];

 87         str3[j] = ch;

 88     }

 89 }

 90 void Minus(char *str1, char *str2, char *str3)

 91 {

 92     // str3 = str1-str2 (str1 > str2)

 93     int i, j, i1, i2, tmp, carry;

 94     int len1 = strlen(str1), len2 = strlen(str2);

 95     char ch;

 96     i1 = len1-1;

 97     i2 = len2-1;

 98     j = carry = 0;

 99     while( i2 >= 0 )

100     {

101         //处理小数str2

102         tmp = str1[i1]-str2[i2]-carry;

103         if( tmp < 0 )

104         {

105             str3[j] = tmp+10+'0';

106             carry = 1;

107         }

108         else

109         {

110             str3[j] = tmp+'0';

111             carry = 0;

112         }

113         --i1;

114         --i2;

115         ++j;

116     }

117     while( i1 >= 0 )

118     {

119         //处理大数str1的剩余部分

120         tmp = str1[i1]-'0'-carry;

121         if( tmp < 0 )

122         {

123             str3[j] = tmp+10+'0';

124             carry = 1;

125         }

126         else

127         {

128             str3[j] = tmp+'0';

129             carry = 0;

130         }

131         --i1;

132         ++j;

133     }

134     --j;

135     //删除数字的前导0

136     while( str3[j] == '0' && j > 0 ) --j;

137     str3[++j] = '\0';

138     for( i=0, --j; i < j; ++i, --j )

139     {

140         // 逆序结果

141         ch = str3[i];

142         str3[i] = str3[j];

143         str3[j] = ch;

144     }

145 }

146 

147 void Mul(char *str1, char *str2, char *str3)

148 {

149     int i, j, i1, i2, tmp, carry, jj;

150     int len1 = strlen(str1), len2 = strlen(str2);

151     char ch;

152     jj = carry = 0;

153     // jj 从最后1位向前依次处理每1位

154 

155     for( i1=len1-1; i1 >= 0; --i1 )

156     {

157         j = jj;  //j从jj开始依次处理每1位

158         for( i2=len2-1; i2 >= 0; --i2, ++j )

159         {

160             tmp = (str3[j]-'0')+(str1[i1]-'0')*(str2[i2]-'0')+carry;

161             if( tmp > 9 )

162             {

163                 carry = tmp/10;

164                 str3[j] = tmp%10+'0';

165             }

166             else

167             {

168                 str3[j] = tmp+'0';

169                 carry = 0;

170             }

171         }

172         if( carry )

173         {

174             //最高位进位

175             str3[j] = carry+'0';

176             carry = 0;

177             ++j;

178         }

179         ++jj;

180     }

181     --j;

182     //去掉尾部0,即乘法结果的前导0

183     while( str3[j] == '0' && j > 0 ) --j;

184     str3[++j] = '\0';

185     for( i=0, --j; i < j; ++i, --j )

186     {

187         ch = str3[i];

188         str3[i] = str3[j];

189         str3[j] = ch;

190     }

191 }

192 

193 void Div(char *str1, char *str2, char *str3,char *str4)

194 {

195     int i1, i2, i, j, jj, tag, carry, cf, c[MAXSIZE];

196     //c 存商

197     int len1 = strlen(str1), len2 = strlen(str2), lend;

198     char d[MAXSIZE];

199     //d  当前被除数,

200     memset(c, 0, sizeof(c));

201     memcpy(d, str1, len2);

202     lend = len2;

203     j = 0; //商的位数,含前导0

204     for( i1=len2-1; i1 < len1; ++i1 )

205     {

206         //i1:商在原被除数的位置

207         if( lend < len2 )

208         {

209             //被除数位数小于除数位数,扩充被除数位数

210             d[lend] = str1[i1+1];

211             c[j] = 0;

212             ++j;

213             ++lend;

214         }

215         else if( lend == len2 )

216         {

217             jj = 1;//被除数与除数位数相同且大于除数

218             for( i=0; i < lend; ++i )

219             {

220                 if( d[i] > str2[i] ) break;

221                 else if( d[i] < str2[i] )

222                 {

223                     jj = 0;

224                     break;

225                 }

226             }

227             if( jj == 0 )

228             {

229                 //被除数小于除数,被除数再扩充一位

230                 d[lend] = str1[i1+1];

231                 c[j] = 0;

232                 ++j;

233                 ++lend;

234                 continue;

235             }

236         }

237         if( jj==1 || lend > len2 )

238         {

239             //被除数大于除数,或者长度比除数多1位

240             cf = jj=0;

241             //cf : 是否可以进行除法

242             while( d[jj] <= '0' && jj < lend ) ++jj;

243             //找到被除数的第一个非0数字

244             if( lend-jj > len2 )

245                 cf = 1;  //被除数长度大于除数

246             else if( lend-jj < len2 )

247                 cf = 0; //被除数长度小于除数

248             else

249             {

250                 //被除数长度等于除数

251                 i2 = 0;

252                 cf = 1;

253                 for( i=jj; i < lend; ++i )

254                 {

255                     if( d[i] < str2[i2] )

256                     {

257                         //被除数小于除数

258                         cf = 0;

259                         break;

260                     }

261                     else if( d[i] > str2[i2] )

262                     {

263                         break;

264                     }

265                     ++i2;

266                 }

267             }//else

268             while( cf )

269             {

270                 //被除数大于除数,求被除数/除数的商(商是1位数)

271                 i2 = len2-1;

272                 cf = 0;

273                 for( i=lend-1; i >= lend-len2; --i )

274                 {

275                     //从末位向前 被除数-除数

276                     d[i] = d[i]-str2[i2]+'0';

277                     if( d[i] < '0' )

278                     {

279                         d[i] = d[i]+10;

280                         carry = 1;

281                         --d[i-1];

282                     }

283                     else carry = 0;

284                     --i2;

285                 }

286                 ++c[j]; //累计可以的(被除数-除数)的次数,即商

287                 //以下代码与上面部分重复,判断被除数是否大于除数

288                 jj=0;

289                 while( d[jj] <= '0' && jj < lend ) ++jj;

290                 if( lend-jj > len2 ) cf = 1;

291                 else if( lend-jj < len2 ) cf = 0;

292                 else

293                 {

294                     i2 = 0;

295                     cf = 1;

296                     for( i=jj; i < lend; ++i )

297                     {

298                         if( d[i] < str2[i2] )

299                         {

300                             cf = 0;

301                             break;

302                         }

303                         else if( d[i] > str2[i2] )

304                         {

305                             break;

306                         }

307                         ++i2;

308                     }

309                 }//else

310             }//while

311 

312             jj = 0;

313             //整理余数,得到新的被除数

314             while( d[jj] <= '0' && jj < lend ) ++jj;

315             for( i=0; i < lend-jj; ++i ) d[i] = d[i+jj];

316             d[i] = str1[i1+1];

317             lend = i+1;

318             ++j;

319         }//if

320     }//for

321     i = tag = 0;

322     while( c[i] == 0 ) ++i;

323     for( ; i < j; ++i, ++tag ) str3[tag] = c[i]+'0';

324     str3[tag] = '\0';

325 //以下内容补充 by lyh:13/5/19

326 // 数组d 保存余数 

327     i = tag = 0;

328     while( d[i] == '0' ) ++i;

329     while( d[i] != '\0' )

330         str4[tag++] = d[i++];

331     str4[tag] = '\0';

332 //商为0时正确返回

333     if(str3[0]=='\0')

334     {

335         str3[0]='0';

336         str3[1]='\0';

337     }

338 //余数为0时正确返回

339     if(str4[0]=='\0')

340     {

341         str4[0]='0';

342         str4[1]='\0';

343     }

344 }

代码很长,中间代码有冗余,应该还可以优化。

这是一位一位的计算。

第二个,比较高效的大数运算:

  1 #include <stdio.h>

  2 #include <string.h>

  3 /*==================================================*\

  4 

  5  | 比较高效的大数

  6  | < , <= , + , - , * , / , %(修改/的最后一行可得)

  7 

  8 \*==================================================*/

  9 

 10 const int base = 10000;    // (base^2) fit into int

 11 const int width = 4;       // width = log base

 12 const int N  = 1000;       // n * width: 可表示的最大位数

 13 struct bint

 14 {

 15     int ln, v[N];

 16     bint (int r = 0)   // r应该是字符串!

 17     {

 18         for (ln = 0; r > 0; r /= base) v[ln++] = r % base;

 19     }

 20     bint& operator = (const bint& r)

 21     {

 22         memcpy(this, &r, (r.ln + 1) * sizeof(int));// !

 23         return *this;

 24     }

 25 } ;

 26 

 27 bool operator < (const bint& a, const bint& b)

 28 {

 29     int i;

 30     if (a.ln != b.ln) return a.ln < b.ln;

 31     for (i = a.ln - 1; i >= 0 && a.v[i] == b.v[i]; i--);

 32     return i < 0 ? 0 : a.v[i] < b.v[i];

 33 }

 34 

 35 bool operator <= (const bint& a, const bint& b)

 36 {

 37     return !(b < a);

 38 }

 39 

 40 bint operator + (const bint& a, const bint& b)

 41 {

 42     bint res;

 43     int i, cy = 0;

 44     for (i = 0; i < a.ln || i < b.ln || cy > 0; i++)

 45     {

 46         if (i < a.ln) cy += a.v[i];

 47         if (i < b.ln) cy += b.v[i];

 48         res.v[i] = cy % base;

 49         cy /= base;

 50     }

 51     res.ln = i;

 52     return res;

 53 }

 54 

 55 bint operator - (const bint& a, const bint& b)

 56 {

 57     bint res;

 58     int i, cy = 0;

 59     for (res.ln = a.ln, i = 0; i < res.ln; i++)

 60     {

 61         res.v[i] = a.v[i] - cy;

 62         if (i < b.ln) res.v[i] -= b.v[i];

 63         if (res.v[i] < 0) cy = 1, res.v[i] += base;

 64         else cy = 0;

 65     }

 66         //去掉结果的前导0,同时修正长度

 67     while (res.ln > 0 && res.v[res.ln - 1] == 0) res.ln--;

 68     return res;

 69 }

 70 

 71 bint operator * (const bint& a, const bint& b)

 72 {

 73     bint res;

 74     res.ln = 0;

 75     if (0 == b.ln)

 76     {

 77         res.v[0] = 0;

 78         return res;

 79     }

 80     int i, j, cy;

 81     for (i = 0; i < a.ln; i++)

 82     {

 83         for (j=cy=0; j < b.ln || cy > 0; j++, cy/= base)

 84         {

 85             if (j < b.ln) cy += a.v[i] * b.v[j];

 86             if (i + j < res.ln) cy += res.v[i + j];

 87             if (i + j >= res.ln) res.v[res.ln++] = cy % base;

 88             else res.v[i + j] = cy % base;

 89         }

 90     }

 91     return res;

 92 }

 93 bint operator / (const bint& a, const bint& b)

 94 {    // ! b != 0

 95     bint tmp, mod, res;

 96     int i, lf, rg, mid;

 97     mod.v[0] = mod.ln = 0;

 98     for (i = a.ln - 1; i >= 0; i--)

 99     {

100         mod = mod * base + a.v[i];

101                 //试商,找到最大的商

102         for (lf = 0, rg = base -1; lf < rg; )

103         {

104             mid = (lf + rg + 1) / 2;

105             if (b * mid <= mod) lf = mid;

106             else rg = mid - 1;

107         }

108         res.v[i] = lf; //

109         mod = mod - b * lf; //余数

110     }

111     res.ln = a.ln;

112     while (res.ln > 0 && res.v[res.ln - 1] == 0) res.ln--;

113     return res;          // return mod 就是%运算

114 }

115 int digits(bint& a)          // 返回位数

116 {

117     if (a.ln == 0) return 0;

118     int l = ( a.ln - 1 ) * 4;

119         //最高位可能不足4位,需要逐位确定

120     for (int t = a.v[a.ln - 1]; t; ++l, t/=10) ;

121     return l;

122 }

123 bool read(bint& b, char buf[])  // 读取失败返回0

124 {

125     if (1 != scanf("%s", buf)) return 0;

126     int w, u, ln = strlen(buf);

127     memset(&b, 0, sizeof(bint));

128     if ('0' == buf[0] && 0 == buf[1]) return 1;

129     for (w = 1, u = 0; ln; )

130     {

131         u += (buf[--ln] - '0') * w;

132         if (w * 10 == base)

133         {

134             b.v[b.ln++] = u;

135             u = 0;

136             w = 1;

137         }

138         else w *= 10;

139     }

140     if (w != 1) b.v[b.ln++] = u;

141     return 1;

142 }

143 

144 void write(const bint& v)

145 {

146     int i;

147     printf("%d", v.ln == 0 ? 0 : v.v[v.ln - 1]);

148     for (i = v.ln - 2; i >= 0; i--)

149         printf("%04d", v.v[i]);  // ! 4 == width

150     printf("\n");

151 }

152 

153 int main(){

154     const int MAXSIZE = 200;

155     char str1[MAXSIZE];

156     bint b1,b2,b3,b4;

157     read(b1, str1);

158     read(b2, str1);

159     b3=b1+b2;

160     write(b3);

161     b3=b1-b2;

162     write(b3);

163     b3=b1*b2;

164     write(b3);

165     b3=b1/b2;

166     write(b3);

167 

168     return 0;

169 }

  与第一个不同的是,每四位每四位的计算,计算的时候不是用字符串计算,而是直接用原来的除法运算,因为原来的一定要快,大数运算的时候能用原来的加减乘除运算就尽量用原来的。为什么划出四位来,因为9999*9999约等于10^8,而int型数据最高不过能储存10^9位数,当然你也可以用64数运算(longlong)。

  另外每四位除法运算的时候是用二分法试商,小学老师教我们的时候能凑出来就凑出来,因为基本一眼就看出来了,而正规的做法应该是不断二分试商,直到上界和下界交叉或等于的时候,那个结果就是正确结果。

 第三个,老师提了一下,思路和第二个差不多,只不过更加细化,加了一些东西,老师说“感觉上更快一些”,名字是《捡来的一个大数模板》,来自网络:

  1 //http://www.cnblogs.com/cj695/archive/2012/07/28/2613678.html

  2 #include <iostream>    

  3 #include <cstring>    

  4 using namespace std;    

  5     

  6 #define DIGIT   4      //四位隔开,即万进制    

  7 #define DEPTH   10000        //万进制    

  8 #define MAX     251    //题目最大位数/4,要不大直接设为最大位数也行 

  9 typedef int bignum_t[MAX+1];    //a[0] 用作临时变量

 10      

 11 /************************************************************************/   

 12 /* 读取操作数,对操作数进行处理存储在数组里                             */   

 13 /************************************************************************/   

 14 int read(bignum_t a,istream&is=cin)    

 15 {    

 16     char buf[MAX*DIGIT+1],ch ;    

 17     int i,j ;    

 18     memset((void*)a,0,sizeof(bignum_t));    

 19     if(!(is>>buf))return 0 ;    

 20 //字符串buf逆序,a[0] 初始化为字符串长度

 21     for(a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)    

 22     ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch ;    

 23 //把数据补足为4(DIGIT)位 ,前面+0

 24     for(a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');    

 25 //将buf中数据每4个一组依次存入a 

 26     for(i=1;i<=a[0];i++)    

 27     for(a[i]=0,j=0;j<DIGIT;j++)    

 28     a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0' ;    

 29 //取掉数字的前导0

 30     for(;!a[a[0]]&&a[0]>1;a[0]--);    

 31     return 1 ;    

 32 }    

 33      

 34 void write(const bignum_t a,ostream&os=cout)    

 35 {    

 36     int i,j ;    

 37 //逆序输出数组 a[],高位在后

 38     for(os<<a[i=a[0]],i--;i;i--)    

 39 //输出每个a[i]的前导0,如果 a[i]=123,输出 0123,补足4位

 40     for(j=DEPTH/10;j;j/=10)    

 41     os<<a[i]/j%10 ;    

 42 }     

 43      

 44 int comp(const bignum_t a,const bignum_t b)    

 45 {    

 46     int i ;    

 47 //长度不相同

 48     if(a[0]!=b[0])     

 49     return a[0]-b[0];    

 50 //从高到低逐位比较

 51     for(i=a[0];i;i--)    

 52     if(a[i]!=b[i])    

 53     return a[i]-b[i];    

 54     return 0 ;    

 55 }    

 56      

 57 int comp(const bignum_t a,const int b)    

 58 {    

 59     int c[12]=    

 60     {    

 61         1     

 62     }    

 63     ;

 64 //把整数 b 转换为 4个一组的万进制存贮      

 65     for(c[1]=b;c[c[0]]>=DEPTH;c[c[0]+1]=c[c[0]]/DEPTH,c[c[0]]%=DEPTH,c[0]++);    

 66 //调用其他重载

 67     return comp(a,c);    

 68 }    

 69      

 70 int comp(const bignum_t a,const int c,const int d,const bignum_t b)    

 71 {    

 72 // 测试 a * c 是否大于b ,d 表示 

 73     int i,t=0,O=-DEPTH*2 ;    

 74     if(b[0]-a[0]<d&&c)    

 75     return 1 ;    

 76     for(i=b[0];i>d;i--)    

 77     {    

 78         t=t*DEPTH+a[i-d]*c-b[i];    

 79         if(t>0)return 1 ;    

 80         if(t<O)return 0 ;    

 81     }    

 82     for(i=d;i;i--)    

 83     {    

 84         t=t*DEPTH-b[i];    

 85         if(t>0)return 1 ;    

 86         if(t<O)return 0 ;    

 87     }    

 88     return t>0 ;    

 89 }    

 90 /************************************************************************/   

 91 /* 大数与大数相加                                                       */   

 92 /************************************************************************/   

 93 void add(bignum_t a,const bignum_t b)    

 94 {    

 95     int i ;    

 96     for(i=1;i<=b[0];i++)    

 97     if((a[i]+=b[i])>=DEPTH)    

 98     a[i]-=DEPTH,a[i+1]++;    

 99     if(b[0]>=a[0])    

100     a[0]=b[0];    

101     else    

102     for(;a[i]>=DEPTH&&i<a[0];a[i]-=DEPTH,i++,a[i]++);    

103     a[0]+=(a[a[0]+1]>0);    

104 }    

105 /************************************************************************/   

106 /* 大数与小数相加                                                       */   

107 /************************************************************************/   

108 void add(bignum_t a,const int b)    

109 {    

110     int i=1 ;    

111     for(a[1]+=b;a[i]>=DEPTH&&i<a[0];a[i+1]+=a[i]/DEPTH,a[i]%=DEPTH,i++);    

112     for(;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);    

113 }    

114 /************************************************************************/   

115 /* 大数相减(被减数>=减数)                                               */   

116 /************************************************************************/   

117 void sub(bignum_t a,const bignum_t b)    

118 {    

119     int i ;    

120     for(i=1;i<=b[0];i++)    

121     if((a[i]-=b[i])<0)    

122     a[i+1]--,a[i]+=DEPTH ;    

123     for(;a[i]<0;a[i]+=DEPTH,i++,a[i]--);    

124     for(;!a[a[0]]&&a[0]>1;a[0]--);    

125 }    

126 /************************************************************************/   

127 /* 大数减去小数(被减数>=减数)                                           */   

128 /************************************************************************/   

129 void sub(bignum_t a,const int b)    

130 {    

131     int i=1 ;    

132     for(a[1]-=b;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);    

133     for(;!a[a[0]]&&a[0]>1;a[0]--);    

134 }    

135      

136 void sub(bignum_t a,const bignum_t b,const int c,const int d)    

137 {    

138     int i,O=b[0]+d ;    

139     for(i=1+d;i<=O;i++)    

140     if((a[i]-=b[i-d]*c)<0)    

141     a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH ;    

142     for(;a[i]<0;a[i+1]+=(a[i]-DEPTH+1)/DEPTH,a[i]-=(a[i]-DEPTH+1)/DEPTH*DEPTH,i++);    

143     for(;!a[a[0]]&&a[0]>1;a[0]--);    

144 }    

145 /************************************************************************/   

146 /* 大数相乘,读入被乘数a,乘数b,结果保存在c[]                          */   

147 /************************************************************************/   

148 void mul(bignum_t c,const bignum_t a,const bignum_t b)    

149 {    

150     int i,j ;    

151     memset((void*)c,0,sizeof(bignum_t));    

152     for(c[0]=a[0]+b[0]-1,i=1;i<=a[0];i++)    

153     for(j=1;j<=b[0];j++)    

154     if((c[i+j-1]+=a[i]*b[j])>=DEPTH)    

155     c[i+j]+=c[i+j-1]/DEPTH,c[i+j-1]%=DEPTH ;    

156     for(c[0]+=(c[c[0]+1]>0);!c[c[0]]&&c[0]>1;c[0]--);    

157 }    

158 /************************************************************************/   

159 /* 大数乘以小数,读入被乘数a,乘数b,结果保存在被乘数                   */   

160 /************************************************************************/   

161 void mul(bignum_t a,const int b)    

162 {    

163     int i ;    

164     for(a[1]*=b,i=2;i<=a[0];i++)    

165     {    

166         a[i]*=b ;    

167         if(a[i-1]>=DEPTH)    

168         a[i]+=a[i-1]/DEPTH,a[i-1]%=DEPTH ;    

169     }    

170     for(;a[a[0]]>=DEPTH;a[a[0]+1]=a[a[0]]/DEPTH,a[a[0]]%=DEPTH,a[0]++);    

171     for(;!a[a[0]]&&a[0]>1;a[0]--);    

172 }    

173      

174 void mul(bignum_t b,const bignum_t a,const int c,const int d)    

175 {    

176     int i ;    

177     memset((void*)b,0,sizeof(bignum_t));    

178     for(b[0]=a[0]+d,i=d+1;i<=b[0];i++)    

179     if((b[i]+=a[i-d]*c)>=DEPTH)    

180     b[i+1]+=b[i]/DEPTH,b[i]%=DEPTH ;    

181     for(;b[b[0]+1];b[0]++,b[b[0]+1]=b[b[0]]/DEPTH,b[b[0]]%=DEPTH);    

182     for(;!b[b[0]]&&b[0]>1;b[0]--);    

183 }    

184 /**************************************************************************/   

185 /* 大数相除,读入被除数a,除数b,结果保存在c[]数组                         */   

186 /* 需要comp()函数                                                         */   

187 /**************************************************************************/   

188 void div(bignum_t c,bignum_t a,const bignum_t b)    

189 {    

190     int h,l,m,i ;    

191     memset((void*)c,0,sizeof(bignum_t));    

192     c[0]=(b[0]<a[0]+1)?(a[0]-b[0]+2):1 ;    

193     for(i=c[0];i;sub(a,b,c[i]=m,i-1),i--)    

194     for(h=DEPTH-1,l=0,m=(h+l+1)>>1;h>l;m=(h+l+1)>>1)    

195     if(comp(b,m,i-1,a))h=m-1 ;    

196     else l=m ;    

197     for(;!c[c[0]]&&c[0]>1;c[0]--);    

198     c[0]=c[0]>1?c[0]:1 ;    

199 }    

200      

201 void div(bignum_t a,const int b,int&c)    

202 {    

203     int i ;    

204     for(c=0,i=a[0];i;c=c*DEPTH+a[i],a[i]=c/b,c%=b,i--);    

205     for(;!a[a[0]]&&a[0]>1;a[0]--);    

206 }    

207 /************************************************************************/   

208 /* 大数平方根,读入大数a,结果保存在b[]数组里                           */   

209 /* 需要comp()函数                                                       */   

210 /************************************************************************/   

211 void sqrt(bignum_t b,bignum_t a)    

212 {    

213     int h,l,m,i ;    

214     memset((void*)b,0,sizeof(bignum_t));    

215     for(i=b[0]=(a[0]+1)>>1;i;sub(a,b,m,i-1),b[i]+=m,i--)    

216     for(h=DEPTH-1,l=0,b[i]=m=(h+l+1)>>1;h>l;b[i]=m=(h+l+1)>>1)    

217     if(comp(b,m,i-1,a))h=m-1 ;    

218     else l=m ;    

219     for(;!b[b[0]]&&b[0]>1;b[0]--);    

220     for(i=1;i<=b[0];b[i++]>>=1);    

221 }    

222 /************************************************************************/   

223 /* 返回大数的长度                                                       */   

224 /************************************************************************/   

225 int length(const bignum_t a)    

226 {    

227     int t,ret ;    

228     for(ret=(a[0]-1)*DIGIT,t=a[a[0]];t;t/=10,ret++);    

229     return ret>0?ret:1 ;    

230 }    

231 /************************************************************************/   

232 /* 返回指定位置的数字,从低位开始数到第b位,返回b位上的数               */   

233 /************************************************************************/   

234 int digit(const bignum_t a,const int b)    

235 {    

236     int i,ret ;    

237     for(ret=a[(b-1)/DIGIT+1],i=(b-1)%DIGIT;i;ret/=10,i--);    

238     return ret%10 ;    

239 }    

240 /************************************************************************/   

241 /* 返回大数末尾0的个数                                                  */   

242 /************************************************************************/   

243 int zeronum(const bignum_t a)    

244 {    

245     int ret,t ;    

246     for(ret=0;!a[ret+1];ret++);    

247     for(t=a[ret+1],ret*=DIGIT;!(t%10);t/=10,ret++);    

248     return ret ;    

249 }    

250      

251 void comp(int*a,const int l,const int h,const int d)    

252 {    

253     int i,j,t ;    

254     for(i=l;i<=h;i++)    

255     for(t=i,j=2;t>1;j++)    

256     while(!(t%j))    

257     a[j]+=d,t/=j ;    

258 }    

259      

260 void convert(int*a,const int h,bignum_t b)    

261 {    

262     int i,j,t=1 ;    

263     memset(b,0,sizeof(bignum_t));    

264     for(b[0]=b[1]=1,i=2;i<=h;i++)    

265     if(a[i])    

266     for(j=a[i];j;t*=i,j--)    

267     if(t*i>DEPTH)    

268     mul(b,t),t=1 ;    

269     mul(b,t);    

270 }    

271 /************************************************************************/   

272 /* 组合数                                                               */   

273 /************************************************************************/   

274 void combination(bignum_t a,int m,int n)    

275 {    

276     int*t=new int[m+1];    

277     memset((void*)t,0,sizeof(int)*(m+1));    

278     comp(t,n+1,m,1);    

279     comp(t,2,m-n,-1);    

280     convert(t,m,a);    

281     delete[]t ;    

282 }    

283 /************************************************************************/   

284 /* 排列数                                                               */   

285 /************************************************************************/   

286 void permutation(bignum_t a,int m,int n)    

287 {    

288     int i,t=1 ;    

289     memset(a,0,sizeof(bignum_t));    

290     a[0]=a[1]=1 ;    

291     for(i=m-n+1;i<=m;t*=i++)    

292     if(t*i>DEPTH)    

293     mul(a,t),t=1 ;    

294     mul(a,t);    

295 }    

296     

297 #define SGN(x) ((x)>0?1:((x)<0?-1:0))    

298 #define ABS(x) ((x)>0?(x):-(x))    

299      

300 int read(bignum_t a,int&sgn,istream&is=cin)    

301 {    

302     char str[MAX*DIGIT+2],ch,*buf ;    

303     int i,j ;    

304     memset((void*)a,0,sizeof(bignum_t));    

305     if(!(is>>str))return 0 ;    

306     buf=str,sgn=1 ;    

307     if(*buf=='-')sgn=-1,buf++;    

308     for(a[0]=strlen(buf),i=a[0]/2-1;i>=0;i--)    

309     ch=buf[i],buf[i]=buf[a[0]-1-i],buf[a[0]-1-i]=ch ;    

310     for(a[0]=(a[0]+DIGIT-1)/DIGIT,j=strlen(buf);j<a[0]*DIGIT;buf[j++]='0');    

311     for(i=1;i<=a[0];i++)    

312     for(a[i]=0,j=0;j<DIGIT;j++)    

313     a[i]=a[i]*10+buf[i*DIGIT-1-j]-'0' ;    

314     for(;!a[a[0]]&&a[0]>1;a[0]--);    

315     if(a[0]==1&&!a[1])sgn=0 ;    

316     return 1 ;    

317 }    

318 struct bignum     

319 {    

320     bignum_t num ;    

321     int sgn ;    

322     public :    

323     inline bignum()    

324     {    

325         memset(num,0,sizeof(bignum_t));    

326         num[0]=1 ;    

327         sgn=0 ;    

328     }    

329     inline int operator!()    

330     {    

331         return num[0]==1&&!num[1];    

332     }    

333     inline bignum&operator=(const bignum&a)    

334     {    

335         memcpy(num,a.num,sizeof(bignum_t));    

336         sgn=a.sgn ;    

337         return*this ;    

338     }    

339     inline bignum&operator=(const int a)    

340     {    

341         memset(num,0,sizeof(bignum_t));    

342         num[0]=1 ;    

343         sgn=SGN (a);    

344         add(num,sgn*a);    

345         return*this ;    

346     }    

347     ;    

348     inline bignum&operator+=(const bignum&a)    

349     {    

350         if(sgn==a.sgn)add(num,a.num);    

351         else if            

352         (sgn&&a.sgn)    

353         {    

354             int ret=comp(num,a.num);    

355             if(ret>0)sub(num,a.num);    

356             else if(ret<0)    

357             {    

358                 bignum_t t ;    

359                 memcpy(t,num,sizeof(bignum_t));    

360                 memcpy(num,a.num,sizeof(bignum_t));    

361                 sub (num,t);    

362                 sgn=a.sgn ;    

363             }    

364             else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;    

365         }    

366         else if(!sgn)    

367             memcpy(num,a.num,sizeof(bignum_t)),sgn=a.sgn ;    

368         return*this ;    

369     }    

370     inline bignum&operator+=(const int a)    

371     {    

372         if(sgn*a>0)add(num,ABS(a));    

373         else if(sgn&&a)    

374         {    

375             int  ret=comp(num,ABS(a));    

376             if(ret>0)sub(num,ABS(a));    

377             else if(ret<0)    

378             {    

379                 bignum_t t ;    

380                 memcpy(t,num,sizeof(bignum_t));    

381                 memset(num,0,sizeof(bignum_t));    

382                 num[0]=1 ;    

383                 add(num,ABS (a));    

384                 sgn=-sgn ;    

385                 sub(num,t);    

386             }    

387             else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;    

388         }    

389         else if    

390             (!sgn)sgn=SGN(a),add(num,ABS(a));    

391         return*this ;    

392     }    

393     inline bignum operator+(const bignum&a)    

394     {    

395         bignum ret ;    

396         memcpy(ret.num,num,sizeof (bignum_t));    

397         ret.sgn=sgn ;    

398         ret+=a ;    

399         return ret ;    

400     }    

401     inline bignum operator+(const int a)    

402     {    

403         bignum ret ;    

404         memcpy(ret.num,num,sizeof (bignum_t));    

405         ret.sgn=sgn ;    

406         ret+=a ;    

407         return ret ;    

408     }    

409     inline bignum&operator-=(const bignum&a)    

410     {    

411         if(sgn*a.sgn<0)add(num,a.num);    

412         else if            

413         (sgn&&a.sgn)    

414         {    

415             int ret=comp(num,a.num);    

416             if(ret>0)sub(num,a.num);    

417             else if(ret<0)    

418             {    

419                 bignum_t t ;    

420                 memcpy(t,num,sizeof(bignum_t));    

421                 memcpy(num,a.num,sizeof(bignum_t));    

422                 sub(num,t);    

423                 sgn=-sgn ;    

424             }    

425             else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;    

426         }    

427         else if(!sgn)add (num,a.num),sgn=-a.sgn ;    

428         return*this ;    

429     }    

430     inline bignum&operator-=(const int a)    

431     {    

432         if(sgn*a<0)add(num,ABS(a));    

433         else if(sgn&&a)    

434         {    

435             int  ret=comp(num,ABS(a));    

436             if(ret>0)sub(num,ABS(a));    

437             else if(ret<0)    

438             {    

439                 bignum_t t ;    

440                 memcpy(t,num,sizeof(bignum_t));    

441                 memset(num,0,sizeof(bignum_t));    

442                 num[0]=1 ;    

443                 add(num,ABS(a));    

444                 sub(num,t);    

445                 sgn=-sgn ;    

446             }    

447             else memset(num,0,sizeof(bignum_t)),num[0]=1,sgn=0 ;    

448         }    

449         else if    

450             (!sgn)sgn=-SGN(a),add(num,ABS(a));    

451         return*this ;    

452     }    

453     inline bignum operator-(const bignum&a)    

454     {    

455         bignum ret ;    

456         memcpy(ret.num,num,sizeof(bignum_t));    

457         ret.sgn=sgn ;    

458         ret-=a ;    

459         return ret ;    

460     }    

461     inline bignum operator-(const int a)    

462     {    

463         bignum ret ;    

464         memcpy(ret.num,num,sizeof(bignum_t));    

465         ret.sgn=sgn ;    

466         ret-=a ;    

467         return ret ;    

468     }    

469     inline bignum&operator*=(const bignum&a)    

470     {    

471         bignum_t t ;    

472         mul(t,num,a.num);    

473         memcpy(num,t,sizeof(bignum_t));    

474         sgn*=a.sgn ;    

475         return*this ;    

476     }    

477     inline bignum&operator*=(const int a)    

478     {    

479         mul(num,ABS(a));    

480         sgn*=SGN(a);    

481         return*this ;    

482     }    

483     inline bignum operator*(const bignum&a)    

484     {    

485         bignum ret ;    

486         mul(ret.num,num,a.num);    

487         ret.sgn=sgn*a.sgn ;    

488         return ret ;    

489     }    

490     inline bignum operator*(const int a)    

491     {    

492         bignum ret ;    

493         memcpy(ret.num,num,sizeof (bignum_t));    

494         mul(ret.num,ABS(a));    

495         ret.sgn=sgn*SGN(a);    

496         return ret ;    

497     }    

498     inline bignum&operator/=(const bignum&a)    

499     {    

500         bignum_t t ;    

501         div(t,num,a.num);    

502         memcpy (num,t,sizeof(bignum_t));    

503         sgn=(num[0]==1&&!num[1])?0:sgn*a.sgn ;    

504         return*this ;    

505     }    

506     inline bignum&operator/=(const int a)    

507     {    

508         int t ;    

509         div(num,ABS(a),t);    

510         sgn=(num[0]==1&&!num [1])?0:sgn*SGN(a);    

511         return*this ;    

512     }    

513     inline bignum operator/(const bignum&a)    

514     {    

515         bignum ret ;    

516         bignum_t t ;    

517         memcpy(t,num,sizeof(bignum_t));    

518         div(ret.num,t,a.num);    

519         ret.sgn=(ret.num[0]==1&&!ret.num[1])?0:sgn*a.sgn ;    

520         return ret ;    

521     }    

522     inline bignum operator/(const int a)    

523     {    

524         bignum ret ;    

525         int t ;    

526         memcpy(ret.num,num,sizeof(bignum_t));    

527         div(ret.num,ABS(a),t);    

528         ret.sgn=(ret.num[0]==1&&!ret.num[1])?0:sgn*SGN(a);    

529         return ret ;    

530     }    

531     inline bignum&operator%=(const bignum&a)    

532     {    

533         bignum_t t ;    

534         div(t,num,a.num);    

535         if(num[0]==1&&!num[1])sgn=0 ;    

536         return*this ;    

537     }    

538     inline int operator%=(const int a)    

539     {    

540         int t ;    

541         div(num,ABS(a),t);    

542         memset(num,0,sizeof (bignum_t));    

543         num[0]=1 ;    

544         add(num,t);    

545         return t ;    

546     }    

547     inline bignum operator%(const bignum&a)    

548     {    

549         bignum ret ;    

550         bignum_t t ;    

551         memcpy(ret.num,num,sizeof(bignum_t));    

552         div(t,ret.num,a.num);    

553         ret.sgn=(ret.num[0]==1&&!ret.num [1])?0:sgn ;    

554         return ret ;    

555     }    

556     inline int operator%(const int a)    

557     {    

558         bignum ret ;    

559         int t ;    

560         memcpy(ret.num,num,sizeof(bignum_t));    

561         div(ret.num,ABS(a),t);    

562         memset(ret.num,0,sizeof(bignum_t));    

563         ret.num[0]=1 ;    

564         add(ret.num,t);    

565         return t ;    

566     }    

567     inline bignum&operator++()    

568     {    

569         *this+=1 ;    

570         return*this ;    

571     }    

572     inline bignum&operator--()    

573     {    

574         *this-=1 ;    

575         return*this ;    

576     }    

577     ;    

578     inline int operator>(const bignum&a)    

579     {    

580         return sgn>0?(a.sgn>0?comp(num,a.num)>0:1):(sgn<0?(a.sgn<0?comp(num,a.num)<0:0):a.sgn<0);    

581     }    

582     inline int operator>(const int a)    

583     {    

584         return sgn>0?(a>0?comp(num,a)>0:1):(sgn<0?(a<0?comp(num,-a)<0:0):a<0);    

585     }    

586     inline int operator>=(const bignum&a)    

587     {    

588         return sgn>0?(a.sgn>0?comp(num,a.num)>=0:1):(sgn<0?(a.sgn<0?comp(num,a.num)<=0:0):a.sgn<=0);    

589     }    

590     inline int operator>=(const int a)    

591     {    

592         return sgn>0?(a>0?comp(num,a)>=0:1):(sgn<0?(a<0?comp(num,-a)<=0:0):a<=0);    

593     }    

594     inline int operator<(const bignum&a)    

595     {    

596         return sgn<0?(a.sgn<0?comp(num,a.num)>0:1):(sgn>0?(a.sgn>0?comp(num,a.num)<0:0):a.sgn>0);    

597     }    

598     inline int operator<(const int a)    

599     {    

600         return sgn<0?(a<0?comp(num,-a)>0:1):(sgn>0?(a>0?comp(num,a)<0:0):a>0);    

601     }    

602     inline int operator<=(const bignum&a)    

603     {    

604         return sgn<0?(a.sgn<0?comp(num,a.num)>=0:1):(sgn>0?(a.sgn>0?comp(num,a.num)<=0:0):a.sgn>=0);    

605     }    

606     inline int operator<=(const int a)    

607     {    

608         return sgn<0?(a<0?comp(num,-a)>=0:1):    

609         (sgn>0?(a>0?comp(num,a)<=0:0):a>=0);    

610     }    

611     inline int operator==(const bignum&a)    

612     {    

613         return(sgn==a.sgn)?!comp(num,a.num):0 ;    

614     }    

615     inline int operator==(const int a)    

616     {    

617         return(sgn*a>=0)?!comp(num,ABS(a)):0 ;    

618     }    

619     inline int operator!=(const bignum&a)    

620     {    

621         return(sgn==a.sgn)?comp(num,a.num):1 ;    

622     }    

623     inline int operator!=(const int a)    

624     {    

625         return(sgn*a>=0)?comp(num,ABS(a)):1 ;    

626     }    

627     inline int operator[](const int a)    

628     {    

629         return digit(num,a);    

630     }    

631     friend inline istream&operator>>(istream&is,bignum&a)    

632     {    

633         read(a.num,a.sgn,is);    

634         return  is ;    

635     }    

636     friend inline ostream&operator<<(ostream&os,const bignum&a)    

637     {    

638         if(a.sgn<0)    

639             os<<'-' ;    

640         write(a.num,os);    

641         return os ;    

642     }    

643     friend inline bignum sqrt(const bignum&a)    

644     {    

645         bignum ret ;    

646         bignum_t t ;    

647         memcpy(t,a.num,sizeof(bignum_t));    

648         sqrt(ret.num,t);    

649         ret.sgn=ret.num[0]!=1||ret.num[1];    

650         return ret ;    

651     }    

652     friend inline bignum sqrt(const bignum&a,bignum&b)    

653     {    

654         bignum ret ;    

655         memcpy(b.num,a.num,sizeof(bignum_t));    

656         sqrt(ret.num,b.num);    

657         ret.sgn=ret.num[0]!=1||ret.num[1];    

658         b.sgn=b.num[0]!=1||ret.num[1];    

659         return ret ;    

660     }    

661     inline int length()    

662     {    

663         return :: length(num);    

664     }    

665     inline int zeronum()    

666     {    

667         return :: zeronum(num);    

668     }    

669     inline bignum C(const int m,const int n)    

670     {    

671         combination(num,m,n);    

672         sgn=1 ;    

673         return*this ;    

674     }    

675     inline bignum P(const int m,const int n)    

676     {    

677         permutation(num,m,n);    

678         sgn=1 ;    

679         return*this ;    

680     }    

681 };   

682 int main()    

683 {       

684     bignum a,b,c;       

685     cin>>a>>b;      

686     cout<<"加法:"<<a+b<<endl;    

687     cout<<"减法:"<<a-b<<endl;    

688     cout<<"乘法:"<<a*b<<endl;    

689     cout<<"除法:"<<a/b<<endl;       

690     c=sqrt(a);    

691     cout<<"平方根:"<<c<<endl;    

692     cout<<"a的长度:"<<a.length()<<endl;    

693     cout<<"a的末尾0个数:"<<a.zeronum()<<endl<<endl;    

694     cout<<"组合: 从10个不同元素取3个元素组合的所有可能性为"<<c.C(10,3)<<endl;    

695     cout<<"排列: 从10个不同元素取3个元素排列的所有可能性为"<<c.P(10,3)<<endl;    

696     return 0 ;    

697 }

 

你可能感兴趣的:(问题)