00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "config.hpp"
00015
00016 #include <cstddef>
00017
00018 #include "exception.hpp"
00019 #include "bigar.hpp"
00020
00021
00022 namespace Arageli { namespace _Internal
00023 {
00024
00025
00026
00027
00028 inline void divide
00029 (
00030 digit& quotient, digit& remainder,
00031 doubledigit numerator, extendeddigit denominator
00032 )
00033 {
00034 quotient = digit(numerator / (doubledigit)denominator);
00035 remainder = digit(numerator % (doubledigit)denominator);
00036 }
00037
00038
00039 std::size_t do_big_int_to_bdn (digit* a, digit* b, std::size_t n, digit bdn_radix)
00040 {
00041
00042
00043
00044
00045
00046
00047
00048
00049 ARAGELI_ASSERT_1(BASE > bdn_radix);
00050
00051 std::size_t m = 0;
00052
00053 while (n > 0)
00054 {
00055
00056 digit carry = 0;
00057 for(std::size_t j = n; j > 0; j--)
00058 {
00059 doubledigit tmp = doubledigit(carry) * BASE + a[j - 1];
00060 carry = digit(tmp % bdn_radix);
00061 a[j - 1] = digit(tmp / bdn_radix);
00062 }
00063
00064 b[m] = carry;
00065 m++;
00066
00067 if(!a[n - 1])
00068 n--;
00069 }
00070
00071 return m;
00072 }
00073
00074
00075 std::size_t do_bdn_to_big_int (digit* a, digit* b, std::size_t n, digit bdn_radix)
00076 {
00077
00078
00079
00080
00081
00082
00083
00084
00085 ARAGELI_ASSERT_1(BASE > bdn_radix);
00086
00087 std::size_t m = 0;
00088 for(std::size_t i = n; i > 0; i--)
00089 {
00090
00091 digit carry = a[i - 1];
00092
00093 for(std::size_t j = 0; j < m; j++)
00094 {
00095 doubledigit tmp = doubledigit(b[j]) * bdn_radix + carry;
00096 carry = digit(tmp / BASE);
00097 b[j] = digit(tmp % BASE);
00098 }
00099
00100 if(carry)
00101 {
00102 b[m] = carry;
00103 m++;
00104 }
00105 }
00106
00107 return m;
00108 }
00109
00110
00111 #ifdef ARAGELI_DISABLE_PARTICULAR_COMPILER_WARNINGS
00112 #pragma warning (push)
00113 #pragma warning (disable : 4244)
00114 #endif
00115
00116
00117 std::size_t do_add (digit* p1, const digit* p2, std::size_t m, std::size_t n)
00118 {
00119
00120
00121
00122
00123
00124
00125
00126 ARAGELI_ASSERT_1(m >= n);
00127
00128 bit carry = 0;
00129
00130
00131
00132 for(std::size_t i = 0; i < n; i++)
00133 {
00134 doubledigit tmp = doubledigit(p1[i]) + p2[i] + carry;
00135 p1[i] = digit(tmp % BASE);
00136 carry = digit(tmp / BASE);
00137 }
00138
00139
00140
00141 for(std::size_t i = n; i < m; i++)
00142 {
00143 doubledigit tmp = doubledigit(p1[i]) + carry;
00144 p1[i] = digit(tmp % BASE);
00145 carry = digit(tmp / BASE);
00146 if(carry == 0) break;
00147 }
00148
00149 if(carry)
00150 {
00151 p1[m] = 1;
00152 return m + 1;
00153 }
00154 else return m;
00155 }
00156
00157
00158 #ifdef ARAGELI_DISABLE_PARTICULAR_COMPILER_WARNINGS
00159 #pragma warning (pop)
00160 #endif
00161
00162
00163 int do_sub (digit* p1, const digit* p2, std::size_t m, std::size_t n)
00164 {
00165
00166
00167
00168
00169
00170
00171 ARAGELI_ASSERT_1(m >= n);
00172
00173 bit borrow = 0;
00174
00175
00176
00177 for(std::size_t i = 0; i < n; i++)
00178 {
00179 if(extendeddigit(p1[i]) >= extendeddigit(p2[i]) + borrow)
00180 {
00181 p1[i] = p1[i] - p2[i] - borrow;
00182 borrow = 0;
00183 }
00184 else
00185 {
00186 p1[i] = digit(BASE + p1[i] - p2[i] - borrow);
00187 borrow = 1;
00188 }
00189 }
00190
00191 if(borrow == 0)return 0;
00192
00193
00194
00195 for(std::size_t i = n; i < m; i++)
00196 {
00197 if(p1[i] >= borrow)
00198 {
00199 p1[i] = p1[i] - borrow;
00200 return 0;
00201 }
00202 else
00203 {
00204 p1[i] = digit(BASE + p1[i] - borrow);
00205 borrow = 1;
00206 }
00207 }
00208
00209 return 1;
00210 }
00211
00212
00213 std::size_t do_optimize (const digit* a, std::size_t n)
00214 {
00215
00216
00217
00218 for(std::size_t i = n; i > 0; i--)
00219 if(a[i - 1])return i;
00220
00221 return 0;
00222 }
00223
00224
00225 std::size_t do_mult (const digit* u, const digit* v, digit* w, std::size_t m, std::size_t n)
00226 {
00227
00228
00229
00230
00231
00232
00233
00234
00235 for(std::size_t i = 0; i < m; i++)
00236 w[i] = 0;
00237
00238 for(std::size_t j = 0; j < n; j++)
00239 {
00240 digit carry = 0;
00241
00242 for(std::size_t i = 0; i < m; i++)
00243 {
00244 doubledigit tmp = doubledigit(u[i]) * v[j] + w[i + j] + carry;
00245 w[i + j] = digit(tmp % BASE);
00246 carry = digit(tmp / BASE);
00247 }
00248
00249 w[j + m] = carry;
00250 }
00251
00252 return w[m + n - 1];
00253 }
00254
00255
00256 digit do_divide_by_digit (const digit* a, digit* p, std::size_t n, digit d)
00257 {
00258
00259
00260
00261
00262
00263
00264
00265 digit carry = 0;
00266
00267 for(std::size_t i = n; i > 0; i--)
00268 {
00269 doubledigit tmp = doubledigit(carry) * BASE + a[i - 1];
00270 p[i - 1] = digit(tmp / d);
00271 carry = digit(tmp % d);
00272 }
00273
00274 return carry;
00275 }
00276
00277
00278 std::size_t do_divide (digit* u, digit* v, digit* q, std::size_t m, std::size_t n)
00279 {
00280
00281
00282 digit d = digit(BASE / (extendeddigit(v[n-1]) + 1));
00283
00284
00285
00286 digit carry = 0;
00287 for(std::size_t j = 0; j < n; j++)
00288 {
00289 doubledigit tmp = doubledigit(v[j]) * d + carry;
00290 carry = digit(tmp/BASE);
00291 v[j] = digit(tmp%BASE);
00292 }
00293
00294
00295
00296 carry = 0;
00297 for(std::size_t j = 0; j < m; j++)
00298 {
00299 doubledigit tmp = doubledigit(u[j]) * d + carry;
00300 carry = digit(tmp / BASE);
00301 u[j] = digit(tmp % BASE);
00302 }
00303 u[m] = carry;
00304
00305
00306
00307
00308 for(std::size_t j = m; j >= n; j--)
00309 {
00310
00311
00312
00313 digit q_hat, r_hat;
00314
00315 int overflow = 0;
00316
00317 if(u[j] >= v[n-1])
00318 {
00319 q_hat = digit(BASE - 1);
00320 if(doubledigit(v[n-1]) + u[j-1] >= BASE)
00321 overflow = 1;
00322 else
00323 r_hat = v[n-1] + u[j-1];
00324 }
00325 else
00326 divide(q_hat, r_hat, doubledigit(u[j]) * BASE + u[j - 1], v[n - 1]);
00327
00328 if(!overflow)
00329 while
00330 (
00331 doubledigit(v[n - 2]) * q_hat >
00332 doubledigit(r_hat) * BASE + u[j - 2]
00333 )
00334 {
00335 q_hat--;
00336 if(doubledigit(r_hat) + v[n - 1] >= BASE)
00337 break;
00338 r_hat += v[n-1];
00339 }
00340
00341
00342
00343
00344
00345 digit carry = 0;
00346 for(std::size_t i = 0; i < n; i++)
00347 {
00348 digit higher, lower;
00349
00350
00352
00353
00354
00355
00356 divide(higher, lower, doubledigit(v[i]) * q_hat + carry, BASE);
00357
00358
00359
00360 if(u[j + i - n] >= lower)
00361 u[j + i - n] -= lower;
00362 else
00363 {
00364 higher++;
00365 u[j + i - n] = digit(BASE - lower + u[j + i - n]);
00366 }
00367
00368 carry = higher;
00369 }
00370
00371 int borrow;
00372 if(u[j] >= carry)
00373 {
00374 borrow = 0;
00375 u[j] -= carry;
00376 }
00377 else
00378 {
00379 borrow = 1;
00380 u[j] = digit(BASE - carry + u[j]);
00381 }
00382
00383
00384
00385 if(borrow)
00386 {
00387
00388
00389
00390
00391
00392 q_hat--;
00393 digit carry = 0;
00394 for(std::size_t i = 0; i < n; i++)
00395 {
00396 divide
00397 (
00398 carry, u[j + i - n],
00399 doubledigit(u[j + i - n]) + v[i] + carry,
00400 extendeddigit(BASE)
00401 );
00402 }
00403 }
00404
00405
00406 q[j - n] = q_hat;
00407 }
00408
00409
00410
00411
00412 carry = 0;
00413 for(std::size_t j = n; j > 0; j--)
00414 divide(u[j - 1], carry, doubledigit(carry) * BASE + u[j - 1], d);
00415
00416
00417 std::size_t u_len = n;
00418
00419 for(std::size_t j = n; j > 0; j--)
00420 if(u[j - 1])break;
00421 else u_len--;
00422
00423 return u_len;
00424 }
00425
00426
00427 }}