00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00036 #include <assert.h>
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include "debug.h"
00040 #include "mytypes.h"
00041
00042 #include "bigint.h"
00043
00044 static void bigint_sign_comb(bool_t srf_a, bigint_t *a, bool_t srf_b,
00045 bigint_t *b, bigint_t *dest);
00046 static void bigint_add_abs(bigint_t *a, bigint_t *b, bigint_t *dest);
00047 static void bigint_sub_abs(bigint_t *a, bigint_t *b, bigint_t *dest);
00048 static void bigint_shift_mul_dig(bigint_t *a, bigint_word_t b, size_t shift,
00049 bigint_t *dest);
00050
00051 static void bigint_alloc(bigint_t *bigint, size_t length);
00052 static void bigint_refine_len(bigint_t *bigint);
00053
00060 void bigint_init(bigint_t *bigint, int value)
00061 {
00062 size_t length;
00063 size_t idx;
00064 int t;
00065
00066 #ifdef DEBUG_BIGINT_TRACE
00067 printf("Initialize bigint with int value %d.\n", value);
00068 #endif
00069
00070 if (value < 0) {
00071 bigint->negative = b_true;
00072 value = -value;
00073 } else {
00074 bigint->negative = b_false;
00075 }
00076
00077
00078 length = 0;
00079 t = value;
00080 while (t > 0) {
00081 length += 1;
00082 t = t / BIGINT_BASE;
00083 }
00084
00085
00086 bigint_alloc(bigint, length);
00087
00088
00089 t = value;
00090 for (idx = 0; idx < length; ++idx) {
00091 bigint->digit[idx] = t % BIGINT_BASE;
00092 t = t / BIGINT_BASE;
00093 }
00094 }
00095
00101 void bigint_shallow_copy(bigint_t *src, bigint_t *dest)
00102 {
00103 #ifdef DEBUG_BIGINT_TRACE
00104 printf("Shallow copy of bigint.\n");
00105 #endif
00106 dest->negative = src->negative;
00107 dest->digit = src->digit;
00108 dest->length = src->length;
00109 }
00115 void bigint_clone(bigint_t *src, bigint_t *dest)
00116 {
00117 size_t idx;
00118
00119 #ifdef DEBUG_BIGINT_TRACE
00120 printf("Clone bigint.\n");
00121 #endif
00122
00123 dest->negative = src->negative;
00124
00125
00126 bigint_alloc(dest, src->length);
00127
00128
00129 for (idx = 0; idx < dest->length; ++idx)
00130 dest->digit[idx] = src->digit[idx];
00131 }
00132
00138 void bigint_reverse_sign(bigint_t *src, bigint_t *dest)
00139 {
00140 size_t idx;
00141
00142 #ifdef DEBUG_BIGINT_TRACE
00143 printf("Reverse-sign copy of bigint.\n");
00144 #endif
00145
00146 dest->negative = !src->negative;
00147
00148
00149 bigint_alloc(dest, src->length);
00150
00151
00152 for (idx = 0; idx < dest->length; ++idx)
00153 dest->digit[idx] = src->digit[idx];
00154 }
00155
00165 void bigint_destroy(bigint_t *bigint)
00166 {
00167 #ifdef DEBUG_BIGINT_TRACE
00168 printf("Destroy bigint.\n");
00169 #endif
00170 bigint->negative = b_false;
00171
00172 bigint->length = 0;
00173
00174 free(bigint->digit);
00175 bigint->digit = NULL;
00176 }
00177
00188 int bigint_get_value_int(bigint_t *bigint, int *dval)
00189 {
00190 bigint_t vval, diff;
00191 size_t idx;
00192 int val;
00193 bool_t zf;
00194
00195 #ifdef DEBUG_BIGINT_TRACE
00196 printf("Get int value of bigint.\n");
00197 #endif
00198 val = 0;
00199 for (idx = 0; idx < bigint->length; ++idx) {
00200 val = val * BIGINT_BASE + bigint->digit[idx];
00201 }
00202
00203 if (bigint->negative)
00204 val = - val;
00205
00206
00207 bigint_init(&vval, val);
00208
00209 bigint_sub(bigint, &vval, &diff);
00210 zf = bigint_is_zero(&diff);
00211
00212 bigint_destroy(&vval);
00213 bigint_destroy(&diff);
00214
00215
00216 if (zf != b_true)
00217 return EINVAL;
00218
00219 *dval = val;
00220 return EOK;
00221 }
00222
00228 bool_t bigint_is_zero(bigint_t *bigint)
00229 {
00230 #ifdef DEBUG_BIGINT_TRACE
00231 printf("Determine if bigint is zero.\n");
00232 #endif
00233 return (bigint->length == 0);
00234 }
00235
00241 bool_t bigint_is_negative(bigint_t *bigint)
00242 {
00243 #ifdef DEBUG_BIGINT_TRACE
00244 printf("Determine if bigint is negative\n");
00245 #endif
00246
00247 assert(bigint->negative == b_false || bigint->length > 0);
00248
00249 return bigint->negative;
00250 }
00251
00259 void bigint_div_digit(bigint_t *a, bigint_word_t b, bigint_t *quot,
00260 bigint_word_t *rem)
00261 {
00262 size_t lbound;
00263 size_t idx;
00264 bigint_dword_t da, db;
00265 bigint_dword_t q, r;
00266
00267 #ifdef DEBUG_BIGINT_TRACE
00268 printf("Divide bigint by digit.\n");
00269 #endif
00270 lbound = a->length;
00271 bigint_alloc(quot, lbound);
00272
00273 quot->negative = a->negative;
00274
00275 r = 0;
00276 idx = lbound;
00277 while (idx > 0) {
00278 --idx;
00279
00280 da = a->digit[idx] + r * BIGINT_BASE;
00281 db = b;
00282
00283 q = da / db;
00284 r = da % db;
00285
00286 quot->digit[idx] = q;
00287 }
00288
00289 bigint_refine_len(quot);
00290 *rem = r;
00291 }
00292
00302 void bigint_add(bigint_t *a, bigint_t *b, bigint_t *dest)
00303 {
00304 #ifdef DEBUG_BIGINT_TRACE
00305 printf("Add bigints.\n");
00306 #endif
00307 bigint_sign_comb(b_false, a, b_false, b, dest);
00308 }
00309
00319 void bigint_sub(bigint_t *a, bigint_t *b, bigint_t *dest)
00320 {
00321 #ifdef DEBUG_BIGINT_TRACE
00322 printf("Subtract bigints.\n");
00323 #endif
00324 bigint_sign_comb(b_false, a, b_true, b, dest);
00325 }
00326
00336 void bigint_mul(bigint_t *a, bigint_t *b, bigint_t *dest)
00337 {
00338 size_t idx;
00339 bigint_t dprod;
00340 bigint_t sum;
00341 bigint_t tmp;
00342
00343 #ifdef DEBUG_BIGINT_TRACE
00344 printf("Multiply bigints.\n");
00345 #endif
00346 bigint_init(&sum, 0);
00347 for (idx = 0; idx < b->length; ++idx) {
00348 bigint_shift_mul_dig(a, b->digit[idx], idx, &dprod);
00349 bigint_add(&dprod, &sum, &tmp);
00350 bigint_destroy(&dprod);
00351
00352 bigint_destroy(&sum);
00353 bigint_shallow_copy(&tmp, &sum);
00354 }
00355
00356 if (b->negative)
00357 sum.negative = !sum.negative;
00358
00359 bigint_shallow_copy(&sum, dest);
00360 }
00361
00367 void bigint_get_as_string(bigint_t *bigint, char **dptr)
00368 {
00369 static const char digits[] = { '0', '1', '2', '3', '4', '5', '6',
00370 '7', '8', '9' };
00371
00372 bigint_t val, tmp;
00373 bigint_word_t rem;
00374 size_t nchars;
00375 char *str;
00376 size_t idx;
00377
00378 #ifdef DEBUG_BIGINT_TRACE
00379 printf("Convert bigint to string.\n");
00380 #endif
00381 assert(BIGINT_BASE >= 10);
00382
00383
00384 nchars = 0;
00385
00386 if (bigint_is_zero(bigint) || bigint->negative)
00387 nchars += 1;
00388
00389 bigint_clone(bigint, &val);
00390 while (bigint_is_zero(&val) != b_true) {
00391 bigint_div_digit(&val, 10, &tmp, &rem);
00392 bigint_destroy(&val);
00393 bigint_shallow_copy(&tmp, &val);
00394
00395 nchars += 1;
00396 }
00397 bigint_destroy(&val);
00398
00399
00400
00401 str = malloc(nchars * sizeof(char) + 1);
00402 if (str == NULL) {
00403 printf("Memory allocation failed.\n");
00404 exit(1);
00405 }
00406
00407 if (bigint_is_zero(bigint)) {
00408 str[0] = '0';
00409 } else if (bigint->negative) {
00410 str[0] = '-';
00411 }
00412
00413 idx = 1;
00414 bigint_clone(bigint, &val);
00415 while (bigint_is_zero(&val) != b_true) {
00416 bigint_div_digit(&val, 10, &tmp, &rem);
00417 bigint_destroy(&val);
00418 bigint_shallow_copy(&tmp, &val);
00419
00420 str[nchars - idx] = digits[(int) rem];
00421 ++idx;
00422 }
00423
00424 bigint_destroy(&val);
00425 str[nchars] = '\0';
00426 *dptr = str;
00427 }
00428
00433 void bigint_print(bigint_t *bigint)
00434 {
00435 char *str;
00436
00437 #ifdef DEBUG_BIGINT_TRACE
00438 printf("Print bigint.\n");
00439 #endif
00440 bigint_get_as_string(bigint, &str);
00441 printf("%s", str);
00442 free(str);
00443 }
00444
00456 static void bigint_sign_comb(bool_t srf_a, bigint_t *a, bool_t srf_b,
00457 bigint_t *b, bigint_t *dest)
00458 {
00459 bool_t neg_a, neg_b;
00460
00461 #ifdef DEBUG_BIGINT_TRACE
00462 printf("Signed combination of two bigints.\n");
00463 #endif
00464
00465 neg_a = (srf_a != a->negative);
00466 neg_b = (srf_b != b->negative);
00467
00468 if (neg_a == neg_b) {
00469 bigint_add_abs(a, b, dest);
00470 dest->negative = neg_a;
00471 } else {
00472 bigint_sub_abs(a, b, dest);
00473 dest->negative = (neg_a != dest->negative);
00474 }
00475 }
00476
00486 static void bigint_add_abs(bigint_t *a, bigint_t *b, bigint_t *dest)
00487 {
00488 size_t lbound;
00489 size_t idx;
00490 bigint_dword_t da, db;
00491 bigint_dword_t tmp;
00492 bigint_word_t res, carry;
00493
00494 #ifdef DEBUG_BIGINT_TRACE
00495 printf("Add absolute values of bigints.\n");
00496 #endif
00497
00498 lbound = (a->length > b->length ? a->length : b->length) + 1;
00499 dest->negative = b_false;
00500
00501 bigint_alloc(dest, lbound);
00502 carry = 0;
00503
00504 for (idx = 0; idx < lbound; ++idx) {
00505 da = idx < a->length ? a->digit[idx] : 0;
00506 db = idx < b->length ? b->digit[idx] : 0;
00507
00508 tmp = da + db + (bigint_word_t) carry;
00509
00510 carry = (bigint_word_t) (tmp / BIGINT_BASE);
00511 res = (bigint_word_t) (tmp % BIGINT_BASE);
00512
00513 dest->digit[idx] = res;
00514 }
00515
00516
00517 assert(carry == 0);
00518
00519 bigint_refine_len(dest);
00520 }
00521
00531 static void bigint_sub_abs(bigint_t *a, bigint_t *b, bigint_t *dest)
00532 {
00533 size_t lbound;
00534 size_t idx;
00535 bigint_dword_t da, db;
00536 bigint_dword_t tmp;
00537 bigint_word_t res, borrow;
00538
00539 #ifdef DEBUG_BIGINT_TRACE
00540 printf("Subtract absolute values of bigints.\n");
00541 #endif
00542
00543 lbound = a->length > b->length ? a->length : b->length;
00544
00545 bigint_alloc(dest, lbound);
00546 borrow = 0;
00547
00548 for (idx = 0; idx < lbound; ++idx) {
00549 da = idx < a->length ? a->digit[idx] : 0;
00550 db = idx < b->length ? b->digit[idx] : 0;
00551
00552 if (da > db + borrow) {
00553 tmp = da - db - borrow;
00554 borrow = 0;
00555 } else {
00556 tmp = da + BIGINT_BASE - db - borrow;
00557 borrow = 1;
00558 }
00559
00560 res = (bigint_word_t) tmp;
00561 dest->digit[idx] = res;
00562 }
00563
00564 if (borrow != 0) {
00565
00566 dest->negative = b_true;
00567
00568
00569
00570
00571
00572
00573 borrow = 0;
00574
00575 for (idx = 0; idx < lbound; ++idx) {
00576 da = 0;
00577 db = dest->digit[idx];
00578
00579 if (da > db + borrow) {
00580 tmp = da - db - borrow;
00581 borrow = 0;
00582 } else {
00583 tmp = da + BIGINT_BASE - db - borrow;
00584 borrow = 1;
00585 }
00586
00587 res = (bigint_word_t) tmp;
00588 dest->digit[idx] = res;
00589 }
00590
00591
00592 assert(borrow == 1);
00593 } else {
00594 dest->negative = b_false;
00595 }
00596
00597 bigint_refine_len(dest);
00598 }
00599
00606 static void bigint_shift_mul_dig(bigint_t *a, bigint_word_t b, size_t shift,
00607 bigint_t *dest)
00608 {
00609 size_t lbound;
00610 size_t idx;
00611
00612 bigint_dword_t da, db;
00613 bigint_dword_t tmp;
00614 bigint_word_t res, carry;
00615
00616 #ifdef DEBUG_BIGINT_TRACE
00617 printf("Multiply bigint by digit.\n");
00618 #endif
00619
00620 lbound = a->length + shift + 1;
00621 bigint_alloc(dest, lbound);
00622
00623
00624 dest->negative = a->negative;
00625
00626 for (idx = 0; idx < shift; ++idx)
00627 dest->digit[idx] = 0;
00628
00629 carry = 0;
00630 for (idx = 0; idx < lbound - shift; ++idx) {
00631 da = idx < a->length ? a->digit[idx] : 0;
00632 db = b;
00633
00634 tmp = (da * db) + (bigint_word_t) carry;
00635
00636 carry = (bigint_word_t) (tmp / BIGINT_BASE);
00637 res = (bigint_word_t) (tmp % BIGINT_BASE);
00638
00639 dest->digit[shift + idx] = res;
00640 }
00641
00642
00643 assert(carry == 0);
00644
00645 bigint_refine_len(dest);
00646 }
00647
00648
00654 static void bigint_alloc(bigint_t *bigint, size_t length)
00655 {
00656 size_t a_length;
00657
00658 #ifdef DEBUG_BIGINT_TRACE
00659 printf("Allocate bigint digit array.\n");
00660 #endif
00661
00662 if (length == 0)
00663 a_length = 1;
00664 else
00665 a_length = length;
00666
00667 bigint->digit = malloc(a_length * sizeof(bigint_word_t));
00668 if (bigint->digit == NULL) {
00669 printf("Memory allocation failed.\n");
00670 exit(1);
00671 }
00672
00673 bigint->length = length;
00674 }
00675
00682 static void bigint_refine_len(bigint_t *bigint)
00683 {
00684 #ifdef DEBUG_BIGINT_TRACE
00685 printf("Refine bigint length.\n");
00686 #endif
00687 while (bigint->length > 0 && bigint->digit[bigint->length - 1] == 0)
00688 bigint->length -= 1;
00689
00690 if (bigint->length == 0)
00691 bigint->negative = b_false;
00692 }