math.big: implement big.integer in V (#11352)
							parent
							
								
									f8aaf4bf67
								
							
						
					
					
						commit
						dadfda9400
					
				|  | @ -1,2 +0,0 @@ | |||
| This folder contains bn.h and bn.c files | ||||
| from https://github.com/kokke/tiny-bignum-c | ||||
|  | @ -1,664 +0,0 @@ | |||
| /*
 | ||||
| 
 | ||||
| Big number library - arithmetic on multiple-precision unsigned integers. | ||||
| 
 | ||||
| This library is an implementation of arithmetic on arbitrarily large integers. | ||||
| 
 | ||||
| The difference between this and other implementations, is that the data structure | ||||
| has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM), | ||||
| and all memory is allocated statically: no dynamic allocation for better or worse. | ||||
| 
 | ||||
| Primary goals are correctness, clarity of code and clean, portable implementation. | ||||
| Secondary goal is a memory footprint small enough to make it suitable for use in | ||||
| embedded applications. | ||||
| 
 | ||||
| 
 | ||||
| The current state is correct functionality and adequate performance. | ||||
| There may well be room for performance-optimizations and improvements. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| #include <stdio.h> | ||||
| #include <stdbool.h> | ||||
| #include <assert.h> | ||||
| #include "bn.h" | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* Functions for shifting number in-place. */ | ||||
| static void _lshift_one_bit(struct bn* a); | ||||
| static void _rshift_one_bit(struct bn* a); | ||||
| static void _lshift_word(struct bn* a, int nwords); | ||||
| static void _rshift_word(struct bn* a, int nwords); | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* Public / Exported functions. */ | ||||
| void bignum_init(struct bn* n) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     n->array[i] = 0; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_from_int(struct bn* n, DTYPE_TMP i) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   bignum_init(n); | ||||
| 
 | ||||
|   /* Endianness issue if machine is not little-endian? */ | ||||
| #ifdef WORD_SIZE | ||||
|  #if (WORD_SIZE == 1) | ||||
|   n->array[0] = (i & 0x000000ff); | ||||
|   n->array[1] = (i & 0x0000ff00) >> 8; | ||||
|   n->array[2] = (i & 0x00ff0000) >> 16; | ||||
|   n->array[3] = (i & 0xff000000) >> 24; | ||||
|  #elif (WORD_SIZE == 2) | ||||
|   n->array[0] = (i & 0x0000ffff); | ||||
|   n->array[1] = (i & 0xffff0000) >> 16; | ||||
|  #elif (WORD_SIZE == 4) | ||||
|   n->array[0] = i; | ||||
|   DTYPE_TMP num_32 = 32; | ||||
|   DTYPE_TMP tmp = i >> num_32; /* bit-shift with U64 operands to force 64-bit results */ | ||||
|   n->array[1] = tmp; | ||||
|  #endif | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int bignum_to_int(struct bn* n) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   int ret = 0; | ||||
| 
 | ||||
|   /* Endianness issue if machine is not little-endian? */ | ||||
| #if (WORD_SIZE == 1) | ||||
|   ret += n->array[0]; | ||||
|   ret += n->array[1] << 8; | ||||
|   ret += n->array[2] << 16; | ||||
|   ret += n->array[3] << 24;   | ||||
| #elif (WORD_SIZE == 2) | ||||
|   ret += n->array[0]; | ||||
|   ret += n->array[1] << 16; | ||||
| #elif (WORD_SIZE == 4) | ||||
|   ret += n->array[0]; | ||||
| #endif | ||||
| 
 | ||||
|   return ret; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_from_string(struct bn* n, char* str, int nbytes) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
|   require(str, "str is null"); | ||||
|   require(nbytes > 0, "nbytes must be positive"); | ||||
|   require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes"); | ||||
| 
 | ||||
|   bignum_init(n); | ||||
| 
 | ||||
|   DTYPE tmp;                        /* DTYPE is defined in bn.h - uint{8,16,32,64}_t */ | ||||
|   int i = nbytes - (2 * WORD_SIZE); /* index into string */ | ||||
|   int j = 0;                        /* index into array */ | ||||
| 
 | ||||
|   /* reading last hex-byte "MSB" from string first -> big endian */ | ||||
|   /* MSB ~= most significant byte / block ? :) */ | ||||
|   while (i >= 0) | ||||
|   { | ||||
|     tmp = 0; | ||||
|     sscanf(&str[i], SSCANF_FORMAT_STR, &tmp); | ||||
|     n->array[j] = tmp; | ||||
|     i -= (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) back in the string. */ | ||||
|     j += 1;               /* step one element forward in the array. */ | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_to_string(struct bn* n, char* str, int nbytes) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
|   require(str, "str is null"); | ||||
|   require(nbytes > 0, "nbytes must be positive"); | ||||
|   require((nbytes & 1) == 0, "string format must be in hex -> equal number of bytes"); | ||||
| 
 | ||||
|   int j = BN_ARRAY_SIZE - 1; /* index into array - reading "MSB" first -> big-endian */ | ||||
|   int i = 0;                 /* index into string representation. */ | ||||
| 
 | ||||
|   /* reading last array-element "MSB" first -> big endian */ | ||||
|   while ((j >= 0) && (nbytes > (i + 1))) | ||||
|   { | ||||
|     sprintf(&str[i], SPRINTF_FORMAT_STR, n->array[j]); | ||||
|     i += (2 * WORD_SIZE); /* step WORD_SIZE hex-byte(s) forward in the string. */ | ||||
|     j -= 1;               /* step one element back in the array. */ | ||||
|   } | ||||
| 
 | ||||
|   /* Count leading zeros: */ | ||||
|   j = 0; | ||||
|   while (str[j] == '0') | ||||
|   { | ||||
|     j += 1; | ||||
|   } | ||||
|   | ||||
|   /* Move string j places ahead, effectively skipping leading zeros */  | ||||
|   for (i = 0; i < (nbytes - j); ++i) | ||||
|   { | ||||
|     str[i] = str[i + j]; | ||||
|   } | ||||
| 
 | ||||
|   /* Zero-terminate string */ | ||||
|   str[i] = 0; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_dec(struct bn* n) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   DTYPE tmp; /* copy of n */ | ||||
|   DTYPE res; | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     tmp = n->array[i]; | ||||
|     res = tmp - 1; | ||||
|     n->array[i] = res; | ||||
| 
 | ||||
|     if (!(res > tmp)) | ||||
|     { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_inc(struct bn* n) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   DTYPE res; | ||||
|   DTYPE_TMP tmp; /* copy of n */ | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     tmp = n->array[i]; | ||||
|     res = tmp + 1; | ||||
|     n->array[i] = res; | ||||
| 
 | ||||
|     if (res > tmp) | ||||
|     { | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_add(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   DTYPE_TMP tmp; | ||||
|   int carry = 0; | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     tmp = (DTYPE_TMP)a->array[i] + b->array[i] + carry; | ||||
|     carry = (tmp > MAX_VAL); | ||||
|     c->array[i] = (tmp & MAX_VAL); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_sub(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   DTYPE_TMP res; | ||||
|   DTYPE_TMP tmp1; | ||||
|   DTYPE_TMP tmp2; | ||||
|   int borrow = 0; | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     tmp1 = (DTYPE_TMP)a->array[i] + (MAX_VAL + 1); /* + number_base */ | ||||
|     tmp2 = (DTYPE_TMP)b->array[i] + borrow;; | ||||
|     res = (tmp1 - tmp2); | ||||
|     c->array[i] = (DTYPE)(res & MAX_VAL); /* "modulo number_base" == "% (number_base - 1)" if number_base is 2^N */ | ||||
|     borrow = (res <= MAX_VAL); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_mul(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   struct bn row; | ||||
|   struct bn tmp; | ||||
|   int i, j; | ||||
| 
 | ||||
|   bignum_init(c); | ||||
| 
 | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     bignum_init(&row); | ||||
| 
 | ||||
|     for (j = 0; j < BN_ARRAY_SIZE; ++j) | ||||
|     { | ||||
|       if (i + j < BN_ARRAY_SIZE) | ||||
|       { | ||||
|         bignum_init(&tmp); | ||||
|         DTYPE_TMP intermediate = ((DTYPE_TMP)a->array[i] * (DTYPE_TMP)b->array[j]); | ||||
|         bignum_from_int(&tmp, intermediate); | ||||
|         _lshift_word(&tmp, i + j); | ||||
|         bignum_add(&tmp, &row, &row); | ||||
|       } | ||||
|     } | ||||
|     bignum_add(c, &row, c); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_div(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   struct bn current; | ||||
|   struct bn denom; | ||||
|   struct bn tmp; | ||||
| 
 | ||||
|   bignum_from_int(¤t, 1);               // int current = 1;
 | ||||
|   bignum_assign(&denom, b);                   // denom = b
 | ||||
|   bignum_assign(&tmp, a);                     // tmp   = a
 | ||||
| 
 | ||||
|   const DTYPE_TMP half_max = 1 + (DTYPE_TMP)(MAX_VAL / 2); | ||||
|   bool overflow = false; | ||||
|   while (bignum_cmp(&denom, a) != LARGER)     // while (denom <= a) {
 | ||||
|   { | ||||
|     if (denom.array[BN_ARRAY_SIZE - 1] >= half_max) | ||||
|     { | ||||
|       overflow = true; | ||||
|       break; | ||||
|     } | ||||
|     _lshift_one_bit(¤t);                //   current <<= 1;
 | ||||
|     _lshift_one_bit(&denom);                  //   denom <<= 1;
 | ||||
|   } | ||||
|   if (!overflow) | ||||
|   { | ||||
|     _rshift_one_bit(&denom);                  // denom >>= 1;
 | ||||
|     _rshift_one_bit(¤t);                // current >>= 1;
 | ||||
|   } | ||||
|   bignum_init(c);                             // int answer = 0;
 | ||||
| 
 | ||||
|   while (!bignum_is_zero(¤t))           // while (current != 0)
 | ||||
|   { | ||||
|     if (bignum_cmp(&tmp, &denom) != SMALLER)  //   if (dividend >= denom)
 | ||||
|     { | ||||
|       bignum_sub(&tmp, &denom, &tmp);         //     dividend -= denom;
 | ||||
|       bignum_or(c, ¤t, c);              //     answer |= current;
 | ||||
|     } | ||||
|     _rshift_one_bit(¤t);                //   current >>= 1;
 | ||||
|     _rshift_one_bit(&denom);                  //   denom >>= 1;
 | ||||
|   }                                           // return answer;
 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_lshift(struct bn* a, struct bn* b, int nbits) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(nbits >= 0, "no negative shifts"); | ||||
| 
 | ||||
|   bignum_assign(b, a); | ||||
|   /* Handle shift in multiples of word-size */ | ||||
|   const int nbits_pr_word = (WORD_SIZE * 8); | ||||
|   int nwords = nbits / nbits_pr_word; | ||||
|   if (nwords != 0) | ||||
|   { | ||||
|     _lshift_word(b, nwords); | ||||
|     nbits -= (nwords * nbits_pr_word); | ||||
|   } | ||||
| 
 | ||||
|   if (nbits != 0) | ||||
|   { | ||||
|     int i; | ||||
|     for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) | ||||
|     { | ||||
|       b->array[i] = (b->array[i] << nbits) | (b->array[i - 1] >> ((8 * WORD_SIZE) - nbits)); | ||||
|     } | ||||
|     b->array[i] <<= nbits; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_rshift(struct bn* a, struct bn* b, int nbits) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(nbits >= 0, "no negative shifts"); | ||||
|    | ||||
|   bignum_assign(b, a); | ||||
|   /* Handle shift in multiples of word-size */ | ||||
|   const int nbits_pr_word = (WORD_SIZE * 8); | ||||
|   int nwords = nbits / nbits_pr_word; | ||||
|   if (nwords != 0) | ||||
|   { | ||||
|     _rshift_word(b, nwords); | ||||
|     nbits -= (nwords * nbits_pr_word); | ||||
|   } | ||||
| 
 | ||||
|   if (nbits != 0) | ||||
|   { | ||||
|     int i; | ||||
|     for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) | ||||
|     { | ||||
|       b->array[i] = (b->array[i] >> nbits) | (b->array[i + 1] << ((8 * WORD_SIZE) - nbits)); | ||||
|     } | ||||
|     b->array[i] >>= nbits; | ||||
|   } | ||||
|    | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_mod(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   /*
 | ||||
|     Take divmod and throw away div part | ||||
|   */ | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   struct bn tmp; | ||||
| 
 | ||||
|   bignum_divmod(a,b,&tmp,c); | ||||
| } | ||||
| 
 | ||||
| void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d) | ||||
| { | ||||
|   /*
 | ||||
|     Puts a%b in d | ||||
|     and a/b in c | ||||
| 
 | ||||
|     mod(a,b) = a - ((a / b) * b) | ||||
| 
 | ||||
|     example: | ||||
|       mod(8, 3) = 8 - ((8 / 3) * 3) = 2 | ||||
|   */ | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   struct bn tmp; | ||||
| 
 | ||||
|   /* c = (a / b) */ | ||||
|   bignum_div(a, b, c); | ||||
| 
 | ||||
|   /* tmp = (c * b) */ | ||||
|   bignum_mul(c, b, &tmp); | ||||
| 
 | ||||
|   /* c = a - tmp */ | ||||
|   bignum_sub(a, &tmp, d); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_and(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     c->array[i] = (a->array[i] & b->array[i]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_or(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     c->array[i] = (a->array[i] | b->array[i]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_xor(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     c->array[i] = (a->array[i] ^ b->array[i]); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int bignum_cmp(struct bn* a, struct bn* b) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
| 
 | ||||
|   int i = BN_ARRAY_SIZE; | ||||
|   do | ||||
|   { | ||||
|     i -= 1; /* Decrement first, to start with last array element */ | ||||
|     if (a->array[i] > b->array[i]) | ||||
|     { | ||||
|       return LARGER; | ||||
|     } | ||||
|     else if (a->array[i] < b->array[i]) | ||||
|     { | ||||
|       return SMALLER; | ||||
|     } | ||||
|   } | ||||
|   while (i != 0); | ||||
| 
 | ||||
|   return EQUAL; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| int bignum_is_zero(struct bn* n) | ||||
| { | ||||
|   require(n, "n is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     if (n->array[i]) | ||||
|     { | ||||
|       return 0; | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   return 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_pow(struct bn* a, struct bn* b, struct bn* c) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
|   require(c, "c is null"); | ||||
| 
 | ||||
|   struct bn tmp; | ||||
| 
 | ||||
|   bignum_init(c); | ||||
| 
 | ||||
|   if (bignum_cmp(b, c) == EQUAL) | ||||
|   { | ||||
|     /* Return 1 when exponent is 0 -- n^0 = 1 */ | ||||
|     bignum_inc(c); | ||||
|   } | ||||
|   else | ||||
|   { | ||||
|     struct bn bcopy; | ||||
|     bignum_assign(&bcopy, b); | ||||
| 
 | ||||
|     /* Copy a -> tmp */ | ||||
|     bignum_assign(&tmp, a); | ||||
| 
 | ||||
|     bignum_dec(&bcopy); | ||||
|   | ||||
|     /* Begin summing products: */ | ||||
|     while (!bignum_is_zero(&bcopy)) | ||||
|     { | ||||
| 
 | ||||
|       /* c = tmp * tmp */ | ||||
|       bignum_mul(&tmp, a, c); | ||||
|       /* Decrement b by one */ | ||||
|       bignum_dec(&bcopy); | ||||
| 
 | ||||
|       bignum_assign(&tmp, c); | ||||
|     } | ||||
| 
 | ||||
|     /* c = tmp */ | ||||
|     bignum_assign(c, &tmp); | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| void bignum_isqrt(struct bn *a, struct bn* b) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(b, "b is null"); | ||||
| 
 | ||||
|   struct bn low, high, mid, tmp; | ||||
| 
 | ||||
|   bignum_init(&low); | ||||
|   bignum_assign(&high, a); | ||||
|   bignum_rshift(&high, &mid, 1); | ||||
|   bignum_inc(&mid); | ||||
| 
 | ||||
|   while (bignum_cmp(&high, &low) > 0)  | ||||
|   { | ||||
|     bignum_mul(&mid, &mid, &tmp); | ||||
|     if (bignum_cmp(&tmp, a) > 0)  | ||||
|     { | ||||
|       bignum_assign(&high, &mid); | ||||
|       bignum_dec(&high); | ||||
|     } | ||||
|     else  | ||||
|     { | ||||
|       bignum_assign(&low, &mid); | ||||
|     } | ||||
|     bignum_sub(&high,&low,&mid); | ||||
|     _rshift_one_bit(&mid); | ||||
|     bignum_add(&low,&mid,&mid); | ||||
|     bignum_inc(&mid); | ||||
|   } | ||||
|   bignum_assign(b,&low); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| void bignum_assign(struct bn* dst, struct bn* src) | ||||
| { | ||||
|   require(dst, "dst is null"); | ||||
|   require(src, "src is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     dst->array[i] = src->array[i]; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Private / Static functions. */ | ||||
| static void _rshift_word(struct bn* a, int nwords) | ||||
| { | ||||
|   /* Naive method: */ | ||||
|   require(a, "a is null"); | ||||
|   require(nwords >= 0, "no negative shifts"); | ||||
| 
 | ||||
|   int i; | ||||
|   if (nwords >= BN_ARRAY_SIZE) | ||||
|   { | ||||
|     for (i = 0; i < BN_ARRAY_SIZE; ++i) | ||||
|     { | ||||
|       a->array[i] = 0; | ||||
|     } | ||||
|     return; | ||||
|   } | ||||
| 
 | ||||
|   for (i = 0; i < BN_ARRAY_SIZE - nwords; ++i) | ||||
|   { | ||||
|     a->array[i] = a->array[i + nwords]; | ||||
|   } | ||||
|   for (; i < BN_ARRAY_SIZE; ++i) | ||||
|   { | ||||
|     a->array[i] = 0; | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void _lshift_word(struct bn* a, int nwords) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
|   require(nwords >= 0, "no negative shifts"); | ||||
| 
 | ||||
|   int i; | ||||
|   /* Shift whole words */ | ||||
|   for (i = (BN_ARRAY_SIZE - 1); i >= nwords; --i) | ||||
|   { | ||||
|     a->array[i] = a->array[i - nwords]; | ||||
|   } | ||||
|   /* Zero pad shifted words. */ | ||||
|   for (; i >= 0; --i) | ||||
|   { | ||||
|     a->array[i] = 0; | ||||
|   }   | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void _lshift_one_bit(struct bn* a) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = (BN_ARRAY_SIZE - 1); i > 0; --i) | ||||
|   { | ||||
|     a->array[i] = (a->array[i] << 1) | (a->array[i - 1] >> ((8 * WORD_SIZE) - 1)); | ||||
|   } | ||||
|   a->array[0] <<= 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| static void _rshift_one_bit(struct bn* a) | ||||
| { | ||||
|   require(a, "a is null"); | ||||
| 
 | ||||
|   int i; | ||||
|   for (i = 0; i < (BN_ARRAY_SIZE - 1); ++i) | ||||
|   { | ||||
|     a->array[i] = (a->array[i] >> 1) | (a->array[i + 1] << ((8 * WORD_SIZE) - 1)); | ||||
|   } | ||||
|   a->array[BN_ARRAY_SIZE - 1] >>= 1; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -1,123 +0,0 @@ | |||
| #ifndef __BIGNUM_H__ | ||||
| #define __BIGNUM_H__ | ||||
| /*
 | ||||
| 
 | ||||
| Big number library - arithmetic on multiple-precision unsigned integers. | ||||
| 
 | ||||
| This library is an implementation of arithmetic on arbitrarily large integers. | ||||
| 
 | ||||
| The difference between this and other implementations, is that the data structure | ||||
| has optimal memory utilization (i.e. a 1024 bit integer takes up 128 bytes RAM), | ||||
| and all memory is allocated statically: no dynamic allocation for better or worse. | ||||
| 
 | ||||
| Primary goals are correctness, clarity of code and clean, portable implementation. | ||||
| Secondary goal is a memory footprint small enough to make it suitable for use in | ||||
| embedded applications. | ||||
| 
 | ||||
| 
 | ||||
| The current state is correct functionality and adequate performance. | ||||
| There may well be room for performance-optimizations and improvements. | ||||
| 
 | ||||
| */ | ||||
| 
 | ||||
| #include <stdint.h> | ||||
| #include <assert.h> | ||||
| 
 | ||||
| 
 | ||||
| /* This macro defines the word size in bytes of the array that constitues the big-number data structure. */ | ||||
| #ifndef WORD_SIZE | ||||
|   #define WORD_SIZE 4 | ||||
| #endif | ||||
| 
 | ||||
| /* Size of big-numbers in bytes */ | ||||
| #define BN_ARRAY_SIZE    (128 / WORD_SIZE) | ||||
| 
 | ||||
| 
 | ||||
| /* Here comes the compile-time specialization for how large the underlying array size should be. */ | ||||
| /* The choices are 1, 2 and 4 bytes in size with uint32, uint64 for WORD_SIZE==4, as temporary. */ | ||||
| #ifndef WORD_SIZE | ||||
|   #error Must define WORD_SIZE to be 1, 2, 4 | ||||
| #elif (WORD_SIZE == 1) | ||||
|   /* Data type of array in structure */ | ||||
|   #define DTYPE                    uint8_t | ||||
|   /* bitmask for getting MSB */ | ||||
|   #define DTYPE_MSB                ((DTYPE_TMP)(0x80)) | ||||
|   /* Data-type larger than DTYPE, for holding intermediate results of calculations */ | ||||
|   #define DTYPE_TMP                uint32_t | ||||
|   /* sprintf format string */ | ||||
|   #define SPRINTF_FORMAT_STR       "%.02x" | ||||
|   #define SSCANF_FORMAT_STR        "%2hhx" | ||||
|   /* Max value of integer type */ | ||||
|   #define MAX_VAL                  ((DTYPE_TMP)0xFF) | ||||
| #elif (WORD_SIZE == 2) | ||||
|   #define DTYPE                    uint16_t | ||||
|   #define DTYPE_TMP                uint32_t | ||||
|   #define DTYPE_MSB                ((DTYPE_TMP)(0x8000)) | ||||
|   #define SPRINTF_FORMAT_STR       "%.04x" | ||||
|   #define SSCANF_FORMAT_STR        "%4hx" | ||||
|   #define MAX_VAL                  ((DTYPE_TMP)0xFFFF) | ||||
| #elif (WORD_SIZE == 4) | ||||
|   #define DTYPE                    uint32_t | ||||
|   #define DTYPE_TMP                uint64_t | ||||
|   #define DTYPE_MSB                ((DTYPE_TMP)(0x80000000)) | ||||
|   #define SPRINTF_FORMAT_STR       "%.08x" | ||||
|   #define SSCANF_FORMAT_STR        "%8x" | ||||
|   #define MAX_VAL                  ((DTYPE_TMP)0xFFFFFFFF) | ||||
| #endif | ||||
| #ifndef DTYPE | ||||
|   #error DTYPE must be defined to uint8_t, uint16_t uint32_t or whatever | ||||
| #endif | ||||
| 
 | ||||
| 
 | ||||
| /* Custom assert macro - easy to disable */ | ||||
| #define require(p, msg) assert(p && #msg) | ||||
| 
 | ||||
| 
 | ||||
| /* Data-holding structure: array of DTYPEs */ | ||||
| struct bn | ||||
| { | ||||
|   DTYPE array[BN_ARRAY_SIZE]; | ||||
| }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* Tokens returned by bignum_cmp() for value comparison */ | ||||
| enum { SMALLER = -1, EQUAL = 0, LARGER = 1 }; | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| /* Initialization functions: */ | ||||
| void bignum_init(struct bn* n); | ||||
| void bignum_from_int(struct bn* n, DTYPE_TMP i); | ||||
| int  bignum_to_int(struct bn* n); | ||||
| void bignum_from_string(struct bn* n, char* str, int nbytes); | ||||
| void bignum_to_string(struct bn* n, char* str, int maxsize); | ||||
| 
 | ||||
| /* Basic arithmetic operations: */ | ||||
| void bignum_add(struct bn* a, struct bn* b, struct bn* c); /* c = a + b */ | ||||
| void bignum_sub(struct bn* a, struct bn* b, struct bn* c); /* c = a - b */ | ||||
| void bignum_mul(struct bn* a, struct bn* b, struct bn* c); /* c = a * b */ | ||||
| void bignum_div(struct bn* a, struct bn* b, struct bn* c); /* c = a / b */ | ||||
| void bignum_mod(struct bn* a, struct bn* b, struct bn* c); /* c = a % b */ | ||||
| void bignum_divmod(struct bn* a, struct bn* b, struct bn* c, struct bn* d); /* c = a/b, d = a%b */ | ||||
| 
 | ||||
| /* Bitwise operations: */ | ||||
| void bignum_and(struct bn* a, struct bn* b, struct bn* c); /* c = a & b */ | ||||
| void bignum_or(struct bn* a, struct bn* b, struct bn* c);  /* c = a | b */ | ||||
| void bignum_xor(struct bn* a, struct bn* b, struct bn* c); /* c = a ^ b */ | ||||
| void bignum_lshift(struct bn* a, struct bn* b, int nbits); /* b = a << nbits */ | ||||
| void bignum_rshift(struct bn* a, struct bn* b, int nbits); /* b = a >> nbits */ | ||||
| 
 | ||||
| /* Special operators and comparison */ | ||||
| int  bignum_cmp(struct bn* a, struct bn* b);               /* Compare: returns LARGER, EQUAL or SMALLER */ | ||||
| int  bignum_is_zero(struct bn* n);                         /* For comparison with zero */ | ||||
| void bignum_inc(struct bn* n);                             /* Increment: add one to n */ | ||||
| void bignum_dec(struct bn* n);                             /* Decrement: subtract one from n */ | ||||
| void bignum_pow(struct bn* a, struct bn* b, struct bn* c); /* Calculate a^b -- e.g. 2^10 => 1024 */ | ||||
| void bignum_isqrt(struct bn* a, struct bn* b);             /* Integer square root -- e.g. isqrt(5) => 2*/ | ||||
| void bignum_assign(struct bn* dst, struct bn* src);        /* Copy src into dst -- dst := src */ | ||||
| 
 | ||||
| 
 | ||||
| #endif /* #ifndef __BIGNUM_H__ */ | ||||
| 
 | ||||
| 
 | ||||
|  | @ -0,0 +1,379 @@ | |||
| module big | ||||
| 
 | ||||
| import math.util | ||||
| 
 | ||||
| // Compares the magnitude of the two unsigned integers represented the given
 | ||||
| // digit arrays. Returns -1 if a < b, 0 if a == b and +1 if a > b. Here
 | ||||
| // a is operand_a and b is operand_b (for brevity).
 | ||||
| fn compare_digit_array(operand_a []u32, operand_b []u32) int { | ||||
| 	a_len := operand_a.len | ||||
| 	b_len := operand_b.len | ||||
| 	if a_len != b_len { | ||||
| 		return if a_len < b_len { -1 } else { 1 } | ||||
| 	} | ||||
| 	// They have the same number of digits now
 | ||||
| 	// Go from the most significant digit to the least significant one
 | ||||
| 	for index := a_len - 1; index >= 0; index-- { | ||||
| 		a_digit := operand_a[index] | ||||
| 		b_digit := operand_b[index] | ||||
| 		if a_digit != b_digit { | ||||
| 			return if a_digit < b_digit { -1 } else { 1 } | ||||
| 		} | ||||
| 	} | ||||
| 	return 0 | ||||
| } | ||||
| 
 | ||||
| // Add the digits in operand_a and operand_b and stores the result in sum.
 | ||||
| // This function does not perform any allocation and assumes that the storage is
 | ||||
| // large enough. It may affect the last element, based on the presence of a carry
 | ||||
| fn add_digit_array(operand_a []u32, operand_b []u32, mut sum []u32) { | ||||
| 	// Zero length cases
 | ||||
| 	if operand_a.len == 0 { | ||||
| 		for index in 0 .. operand_b.len { | ||||
| 			sum[index] = operand_b[index] | ||||
| 		} | ||||
| 	} | ||||
| 	if operand_b.len == 0 { | ||||
| 		for index in 0 .. operand_a.len { | ||||
| 			sum[index] = operand_a[index] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// First pass intersects with both operands
 | ||||
| 	smaller_limit := util.imin(operand_a.len, operand_b.len) | ||||
| 	larger_limit := util.imax(operand_a.len, operand_b.len) | ||||
| 	mut a, mut b := if operand_a.len >= operand_b.len { | ||||
| 		operand_a, operand_b | ||||
| 	} else { | ||||
| 		operand_b, operand_a | ||||
| 	} | ||||
| 	mut carry := u64(0) | ||||
| 	for index in 0 .. smaller_limit { | ||||
| 		partial := carry + a[index] + b[index] | ||||
| 		sum[index] = u32(partial) | ||||
| 		carry = u32(partial >> 32) | ||||
| 	} | ||||
| 
 | ||||
| 	for index in smaller_limit .. larger_limit { | ||||
| 		partial := carry + a[index] | ||||
| 		sum[index] = u32(partial) | ||||
| 		carry = u32(partial >> 32) | ||||
| 	} | ||||
| 
 | ||||
| 	if carry == 0 { | ||||
| 		sum.delete_last() | ||||
| 	} else { | ||||
| 		sum[larger_limit] = u32(carry) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Subtracts operand_b from operand_a and stores the difference in storage.
 | ||||
| // It assumes operand_a contains the larger "integer" and that storage is
 | ||||
| // the same size as operand_a
 | ||||
| fn subtract_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) { | ||||
| 	// Zero length cases
 | ||||
| 	if operand_a.len == 0 { | ||||
| 		// nothing to subtract from
 | ||||
| 		return | ||||
| 	} | ||||
| 	if operand_b.len == 0 { | ||||
| 		// nothing to subtract
 | ||||
| 		for index in 0 .. operand_a.len { | ||||
| 			storage[index] = operand_a[index] | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	mut carry := false | ||||
| 	for index in 0 .. operand_b.len { | ||||
| 		mut a_digit := u64(operand_a[index]) | ||||
| 		b_digit := operand_b[index] + if carry { u64(1) } else { u64(0) } | ||||
| 		carry = a_digit < b_digit | ||||
| 		if carry { | ||||
| 			a_digit += 0x100000000 | ||||
| 		} | ||||
| 		storage[index] = u32(a_digit - b_digit) | ||||
| 	} | ||||
| 
 | ||||
| 	for index in operand_b.len .. operand_a.len { | ||||
| 		mut a_digit := u64(operand_a[index]) | ||||
| 		b_digit := if carry { u64(1) } else { u64(0) } | ||||
| 		carry = a_digit < b_digit | ||||
| 		if carry { | ||||
| 			a_digit += 0x100000000 | ||||
| 		} | ||||
| 		storage[index] = u32(a_digit - b_digit) | ||||
| 	} | ||||
| 
 | ||||
| 	if storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Multiplies the unsigned (non-negative) integers represented in a and b and the product is
 | ||||
| // stored in storage. It assumes that storage has length equal to the sum of lengths
 | ||||
| // of a and b. Length refers to length of array, that is, digit count.
 | ||||
| fn multiply_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) { | ||||
| 	for b_index in 0 .. operand_b.len { | ||||
| 		mut carry := u64(0) | ||||
| 		for a_index in 0 .. operand_a.len { | ||||
| 			partial_product := u64(storage[a_index + b_index]) + carry + | ||||
| 				u64(operand_a[a_index]) * u64(operand_b[b_index]) | ||||
| 			storage[a_index + b_index] = u32(partial_product) | ||||
| 			carry = partial_product >> 32 | ||||
| 		} | ||||
| 		if carry != 0 { | ||||
| 			storage[b_index + operand_a.len] = u32(carry) | ||||
| 		} | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Stores the product of the unsigned (non-negative) integer represented in a and the digit in value
 | ||||
| // in the storage array. It assumes storage is pre-initialised and populated with 0's
 | ||||
| fn multiply_array_by_digit(operand_a []u32, value u32, mut storage []u32) { | ||||
| 	if value == 0 { | ||||
| 		for storage.len > 0 { | ||||
| 			storage.delete_last() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	if value == 1 { | ||||
| 		for index in 0 .. operand_a.len { | ||||
| 			storage[index] = operand_a[index] | ||||
| 		} | ||||
| 		for storage.len > 0 && storage.last() == 0 { | ||||
| 			storage.delete_last() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	mut carry := u32(0) | ||||
| 	for index in 0 .. operand_a.len { | ||||
| 		product := u64(operand_a[index]) * value + carry | ||||
| 		storage[index] = u32(product) | ||||
| 		carry = u32(product >> 32) | ||||
| 	} | ||||
| 	if carry > 0 { | ||||
| 		if storage.last() == 0 { | ||||
| 			storage[operand_a.len] = carry | ||||
| 		} else { | ||||
| 			storage << carry | ||||
| 		} | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Divides the non-negative integer in a by non-negative integer b and store the two results
 | ||||
| // in quotient and remainder respectively. It is different from the rest of the functions
 | ||||
| // because it assumes that quotient and remainder are empty zero length arrays. They can be
 | ||||
| // made to have appropriate capacity though
 | ||||
| fn divide_digit_array(operand_a []u32, operand_b []u32, mut quotient []u32, mut remainder []u32) { | ||||
| 	cmp_result := compare_digit_array(operand_a, operand_b) | ||||
| 	// a == b => q, r = 1, 0
 | ||||
| 	if cmp_result == 0 { | ||||
| 		quotient << 1 | ||||
| 		for quotient.len > 1 { | ||||
| 			quotient.delete_last() | ||||
| 		} | ||||
| 		for remainder.len > 0 { | ||||
| 			remainder.delete_last() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 
 | ||||
| 	// a < b => q, r = 0, a
 | ||||
| 	if cmp_result < 0 { | ||||
| 		for quotient.len > 0 { | ||||
| 			quotient.delete_last() | ||||
| 		} | ||||
| 		for index in 0 .. operand_a.len { | ||||
| 			remainder << operand_a[index] | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	if operand_b.len == 1 { | ||||
| 		divide_array_by_digit(operand_a, operand_b[0], mut quotient, mut remainder) | ||||
| 	} else { | ||||
| 		divide_array_by_array(operand_a, operand_b, mut quotient, mut remainder) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Performs division on the non-negative dividend in a by the single digit divisor b. It assumes
 | ||||
| // quotient and remainder are empty zero length arrays with sufficient capacity
 | ||||
| fn divide_array_by_digit(operand_a []u32, divisor u32, mut quotient []u32, mut remainder []u32) { | ||||
| 	if operand_a.len == 1 { | ||||
| 		// 1 digit for both dividend and divisor
 | ||||
| 		dividend := operand_a[0] | ||||
| 		q := dividend / divisor | ||||
| 		if q != 0 { | ||||
| 			quotient << q | ||||
| 		} | ||||
| 		rem := dividend % divisor | ||||
| 		if rem != 0 { | ||||
| 			remainder << rem | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
| 	// Dividend has more digits
 | ||||
| 	mut rem := u64(0) | ||||
| 	divisor64 := u64(divisor) | ||||
| 	// Pad quotient to contain sufficient space
 | ||||
| 	for _ in 0 .. operand_a.len { | ||||
| 		quotient << 0 | ||||
| 	} | ||||
| 	// Perform division step by step
 | ||||
| 	for index := operand_a.len - 1; index >= 0; index-- { | ||||
| 		dividend := (rem << 32) + operand_a[index] | ||||
| 		quotient[index] = u32(dividend / divisor64) | ||||
| 		rem = dividend % divisor64 | ||||
| 	} | ||||
| 	// Remove leading zeros from quotient
 | ||||
| 	for quotient.len > 0 && quotient.last() == 0 { | ||||
| 		quotient.delete_last() | ||||
| 	} | ||||
| 	remainder << u32(rem) | ||||
| 	for remainder.len > 0 && remainder.last() == 0 { | ||||
| 		remainder.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Performs division on the non-negative dividend in a by the multi digit divisor b. It assumes
 | ||||
| // quotient and remainder are empty zero length arrays with sufficient capacity
 | ||||
| // This is different from divide_digit_array because it depends on this very function
 | ||||
| // after making sure that the divisor is indeed multi-digit.
 | ||||
| fn divide_array_by_array(operand_a []u32, operand_b []u32, mut quotient []u32, mut remainder []u32) { | ||||
| 	for index in 0 .. operand_a.len { | ||||
| 		remainder << operand_a[index] | ||||
| 	} | ||||
| 	for _ in 0 .. operand_b.len { | ||||
| 		quotient << 0 | ||||
| 	} | ||||
| 	offset := operand_a.len - operand_b.len | ||||
| 	divisor_last_index := operand_b.len - 1 | ||||
| 	for index := offset; index >= 0; index-- { | ||||
| 		dividend_last_index := divisor_last_index + index | ||||
| 		value_upper := if remainder.len > dividend_last_index + 1 { | ||||
| 			u64(remainder[dividend_last_index + 1]) | ||||
| 		} else { | ||||
| 			u64(0) | ||||
| 		} | ||||
| 		value_lower := if remainder.len > dividend_last_index { | ||||
| 			u64(remainder[dividend_last_index]) | ||||
| 		} else { | ||||
| 			u64(0) | ||||
| 		} | ||||
| 		partial := value_lower + (value_upper << 32) | ||||
| 		mut q := u32(partial / operand_b[divisor_last_index]) | ||||
| 		if q > 0 { | ||||
| 			mut modified_divisor := []u32{len: operand_b.len + index, init: 0} | ||||
| 			for i in 0 .. operand_b.len { | ||||
| 				modified_divisor[index + i] = operand_b[i] | ||||
| 			} | ||||
| 
 | ||||
| 			mut product := []u32{len: operand_b.len + 1, init: 0} | ||||
| 			multiply_array_by_digit(modified_divisor, q, mut product) | ||||
| 			for q > 0 && compare_digit_array(product, remainder) > 0 { | ||||
| 				q-- | ||||
| 				subtract_digit_array(product, modified_divisor, mut product) | ||||
| 			} | ||||
| 			subtract_digit_array(remainder, product, mut remainder) | ||||
| 		} | ||||
| 		quotient[index] = q | ||||
| 	} | ||||
| 	// Remove leading zeros from quotient and remainder
 | ||||
| 	for quotient.len > 0 && quotient.last() == 0 { | ||||
| 		quotient.delete_last() | ||||
| 	} | ||||
| 	for remainder.len > 0 && remainder.last() == 0 { | ||||
| 		remainder.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Shifts the contents of the original array by the given amount of bits to the left.
 | ||||
| // This function assumes that the amount is less than 32. The storage is expected to
 | ||||
| // allocated with zeroes.
 | ||||
| fn shift_digits_left(original []u32, amount u32, mut storage []u32) { | ||||
| 	mut leftover := u32(0) | ||||
| 	offset := 32 - amount | ||||
| 	for index in 0 .. original.len { | ||||
| 		value := leftover | (original[index] << amount) | ||||
| 		leftover = (original[index] & (u32(-1) << offset)) >> offset | ||||
| 		storage[index] = value | ||||
| 	} | ||||
| 	if leftover != 0 { | ||||
| 		storage << leftover | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // Shifts the contents of the original array by the given amount of bits to the right.
 | ||||
| // This function assumes that the amount is less than 32. The storage is expected to
 | ||||
| // be allocated with zeroes.
 | ||||
| fn shift_digits_right(original []u32, amount u32, mut storage []u32) { | ||||
| 	mut moveover := u32(0) | ||||
| 	mask := (u32(1) << amount) - 1 | ||||
| 	offset := 32 - amount | ||||
| 	for index := original.len - 1; index >= 0; index-- { | ||||
| 		value := (moveover << offset) | (original[index] >> amount) | ||||
| 		moveover = original[index] & mask | ||||
| 		storage[index] = value | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn bitwise_or_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) { | ||||
| 	lower, upper, bigger := if operand_a.len < operand_b.len { | ||||
| 		operand_a.len, operand_b.len, operand_b | ||||
| 	} else { | ||||
| 		operand_b.len, operand_a.len, operand_a | ||||
| 	} | ||||
| 	for index in 0 .. lower { | ||||
| 		storage[index] = operand_a[index] | operand_b[index] | ||||
| 	} | ||||
| 	for index in lower .. upper { | ||||
| 		storage[index] = bigger[index] | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn bitwise_and_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) { | ||||
| 	lower := util.imin(operand_a.len, operand_b.len) | ||||
| 	for index in 0 .. lower { | ||||
| 		storage[index] = operand_a[index] & operand_b[index] | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn bitwise_xor_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) { | ||||
| 	lower, upper, bigger := if operand_a.len < operand_b.len { | ||||
| 		operand_a.len, operand_b.len, operand_b | ||||
| 	} else { | ||||
| 		operand_b.len, operand_a.len, operand_a | ||||
| 	} | ||||
| 	for index in 0 .. lower { | ||||
| 		storage[index] = operand_a[index] ^ operand_b[index] | ||||
| 	} | ||||
| 	for index in lower .. upper { | ||||
| 		storage[index] = bigger[index] | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn bitwise_not_digit_array(original []u32, mut storage []u32) { | ||||
| 	for index in 0 .. original.len { | ||||
| 		storage[index] = ~original[index] | ||||
| 	} | ||||
| 	for storage.len > 0 && storage.last() == 0 { | ||||
| 		storage.delete_last() | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,221 @@ | |||
| module big | ||||
| 
 | ||||
| fn test_add_digit_array_01() { | ||||
| 	a := [u32(1), 1, 1] | ||||
| 	b := [u32(1), 1, 1] | ||||
| 	mut c := []u32{len: 4} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(2), 2, 2] | ||||
| } | ||||
| 
 | ||||
| fn test_add_digit_array_02() { | ||||
| 	a := [u32(1), u32(1) << 31, 1] | ||||
| 	b := [u32(1), u32(1) << 31, 1] | ||||
| 	mut c := []u32{len: 4} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(2), 0, 3] | ||||
| } | ||||
| 
 | ||||
| fn test_add_digit_array_03() { | ||||
| 	a := [u32(1), (u32(1) << 31) + u32(34), 1] | ||||
| 	b := [u32(242), u32(1) << 31, 1] | ||||
| 	mut c := []u32{len: 4} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(243), 34, 3] | ||||
| } | ||||
| 
 | ||||
| fn test_add_digit_array_04() { | ||||
| 	a := [u32(0)] | ||||
| 	b := [u32(1), 3, 4] | ||||
| 	mut c := []u32{len: 4} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(1), 3, 4] | ||||
| } | ||||
| 
 | ||||
| fn test_add_digit_array_05() { | ||||
| 	a := [u32(1), 3, 4] | ||||
| 	b := [u32(0)] | ||||
| 	mut c := []u32{len: 4} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(1), 3, 4] | ||||
| } | ||||
| 
 | ||||
| fn test_add_digit_array_06() { | ||||
| 	a := [u32(46), 13, 462, 13] | ||||
| 	b := [u32(1), 3, 4] | ||||
| 	mut c := []u32{len: 5} | ||||
| 	add_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(47), 16, 466, 13] | ||||
| } | ||||
| 
 | ||||
| fn test_subtract_digit_array_01() { | ||||
| 	a := [u32(2), 2, 2, 2, 2] | ||||
| 	b := [u32(1), 1, 2, 1, 1] | ||||
| 	mut c := []u32{len: a.len} | ||||
| 	subtract_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(1), 1, 0, 1, 1] | ||||
| } | ||||
| 
 | ||||
| fn test_subtract_digit_array_02() { | ||||
| 	a := [u32(0), 0, 0, 0, 1] | ||||
| 	b := [u32(0), 0, 1] | ||||
| 	mut c := []u32{len: a.len} | ||||
| 	subtract_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(0), 0, u32(-1), u32(-1)] | ||||
| } | ||||
| 
 | ||||
| fn test_subtract_digit_array_03() { | ||||
| 	a := [u32(0), 0, 0, 0, 1, 13] | ||||
| 	b := [u32(0), 0, 1] | ||||
| 	mut c := []u32{len: a.len} | ||||
| 	subtract_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(0), 0, u32(-1), u32(-1), 0, 13] | ||||
| } | ||||
| 
 | ||||
| fn test_multiply_digit_array_01() { | ||||
| 	a := [u32(0), 0, 0, 1] | ||||
| 	b := [u32(0), 0, 1] | ||||
| 	mut c := []u32{len: a.len + b.len} | ||||
| 	multiply_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [u32(0), 0, 0, 0, 0, 1] | ||||
| } | ||||
| 
 | ||||
| fn test_multiply_digit_array_02() { | ||||
| 	a := []u32{len: 0} | ||||
| 	b := [u32(0), 0, 1] | ||||
| 	mut c := []u32{len: a.len + b.len} | ||||
| 	multiply_digit_array(a, b, mut c) | ||||
| 
 | ||||
| 	assert c == [] | ||||
| 
 | ||||
| 	c = []u32{len: a.len + b.len} | ||||
| 	multiply_digit_array(b, a, mut c) | ||||
| 
 | ||||
| 	assert c == [] | ||||
| } | ||||
| 
 | ||||
| fn test_compare_digit_array_01() { | ||||
| 	a := [u32(0), 0, 2] | ||||
| 	b := [u32(0), 0, 4] | ||||
| 
 | ||||
| 	assert compare_digit_array(a, b) < 0 | ||||
| 	assert compare_digit_array(b, a) > 0 | ||||
| 	assert compare_digit_array(a, a) == 0 | ||||
| 	assert compare_digit_array(b, b) == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_compare_digit_array_02() { | ||||
| 	a := [u32(0), 0, 2324, 0, 124] | ||||
| 	b := [u32(0), 0, 4, 0, 0, 1] | ||||
| 
 | ||||
| 	assert compare_digit_array(a, b) < 0 | ||||
| 	assert compare_digit_array(b, a) > 0 | ||||
| 	assert compare_digit_array(a, a) == 0 | ||||
| 	assert compare_digit_array(b, b) == 0 | ||||
| } | ||||
| 
 | ||||
| fn test_divide_digit_array_01() { | ||||
| 	a := [u32(14)] | ||||
| 	b := [u32(2)] | ||||
| 	mut q := []u32{cap: 1} | ||||
| 	mut r := []u32{cap: 1} | ||||
| 
 | ||||
| 	divide_digit_array(a, b, mut q, mut r) | ||||
| 	assert q == [u32(7)] | ||||
| 	assert r == []u32{len: 0} | ||||
| } | ||||
| 
 | ||||
| fn test_divide_digit_array_02() { | ||||
| 	a := [u32(14)] | ||||
| 	b := [u32(15)] | ||||
| 	mut q := []u32{cap: 1} | ||||
| 	mut r := []u32{cap: 1} | ||||
| 
 | ||||
| 	divide_digit_array(a, b, mut q, mut r) | ||||
| 	assert q == []u32{len: 0} | ||||
| 	assert r == a | ||||
| } | ||||
| 
 | ||||
| fn test_divide_digit_array_03() { | ||||
| 	a := [u32(0), 4] | ||||
| 	b := [u32(0), 1] | ||||
| 	mut q := []u32{cap: a.len - b.len + 1} | ||||
| 	mut r := []u32{cap: a.len} | ||||
| 
 | ||||
| 	divide_digit_array(a, b, mut q, mut r) | ||||
| 	assert q == [u32(4)] | ||||
| 	assert r == []u32{len: 0} | ||||
| } | ||||
| 
 | ||||
| fn test_divide_digit_array_04() { | ||||
| 	a := [u32(2), 4] | ||||
| 	b := [u32(0), 1] | ||||
| 	mut q := []u32{cap: a.len - b.len + 1} | ||||
| 	mut r := []u32{cap: a.len} | ||||
| 
 | ||||
| 	divide_digit_array(a, b, mut q, mut r) | ||||
| 	assert q == [u32(4)] | ||||
| 	assert r == [u32(2)] | ||||
| } | ||||
| 
 | ||||
| fn test_divide_digit_array_05() { | ||||
| 	a := [u32(3)] | ||||
| 	b := [u32(2)] | ||||
| 	mut q := []u32{cap: a.len - b.len + 1} | ||||
| 	mut r := []u32{cap: a.len} | ||||
| 
 | ||||
| 	divide_digit_array(a, b, mut q, mut r) | ||||
| 	assert q == [u32(1)] | ||||
| 	assert r == [u32(1)] | ||||
| } | ||||
| 
 | ||||
| fn test_left_and_right_shift() { | ||||
| 	a := [u32(1), 1, 1] | ||||
| 	mut r := [u32(2), 2, 2] | ||||
| 	mut b := []u32{len: 3, init: 0} | ||||
| 	shift_digits_left(a, 1, mut b) | ||||
| 	assert r == b | ||||
| 	shift_digits_right(r, 1, mut r) | ||||
| 	assert r == a | ||||
| 	shift_digits_left(r, 1, mut r) | ||||
| 	assert r == b | ||||
| 
 | ||||
| 	mut c := [u32(0xffffffff)] | ||||
| 	shift_digits_left(c, 16, mut c) | ||||
| 	assert c == [u32(0xfffff0000), 0xffff] | ||||
| 	shift_digits_right(c, 8, mut c) | ||||
| 	assert c == [u32(0xfffffff00), 0xff] | ||||
| 	shift_digits_right(c, 16, mut c) | ||||
| 	assert c == [u32(0x00ffffff)] | ||||
| 	shift_digits_right(c, 16, mut c) | ||||
| 	assert c == [u32(0xff)] | ||||
| 	shift_digits_right(c, 16, mut c) | ||||
| 	assert c == []u32{len: 0} | ||||
| } | ||||
| 
 | ||||
| fn test_or_digit_array() { | ||||
| 	a := [u32(10), 10, 10] | ||||
| 	b := [u32(5), 5, 5] | ||||
| 	mut c := []u32{len: 3, init: 0} | ||||
| 	bitwise_or_digit_array(a, b, mut c) | ||||
| 	assert c == [u32(15), 15, 15] | ||||
| 
 | ||||
| 	bitwise_or_digit_array(a, a, mut c) | ||||
| 	assert c == a | ||||
| 
 | ||||
| 	x := [u32(10), 10, 10, 42, 42] | ||||
| 	y := [u32(2), 2, 5, 2] | ||||
| 	mut d := []u32{len: 5, init: 0} | ||||
| 	bitwise_or_digit_array(y, x, mut d) | ||||
| 	assert d == [u32(10), 10, 15, 42, 42] | ||||
| } | ||||
|  | @ -1,344 +0,0 @@ | |||
| module big | ||||
| 
 | ||||
| // Wrapper for https://github.com/kokke/tiny-bignum-c
 | ||||
| #flag -I @VEXEROOT/thirdparty/bignum | ||||
| #flag @VEXEROOT/thirdparty/bignum/bn.o | ||||
| #include "bn.h" | ||||
| 
 | ||||
| struct C.bn { | ||||
| mut: | ||||
| 	array [32]u32 | ||||
| } | ||||
| 
 | ||||
| // Big unsigned integer number.
 | ||||
| type Number = C.bn | ||||
| 
 | ||||
| fn C.bignum_init(n &Number) | ||||
| 
 | ||||
| fn C.bignum_from_int(n &Number, i u64) | ||||
| 
 | ||||
| fn C.bignum_to_int(n &Number) int | ||||
| 
 | ||||
| fn C.bignum_from_string(n &Number, s &char, nbytes int) | ||||
| 
 | ||||
| fn C.bignum_to_string(n &Number, s &char, maxsize int) | ||||
| 
 | ||||
| // c = a + b
 | ||||
| fn C.bignum_add(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a - b
 | ||||
| fn C.bignum_sub(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a * b
 | ||||
| fn C.bignum_mul(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a / b
 | ||||
| fn C.bignum_div(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a % b
 | ||||
| fn C.bignum_mod(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a/b d=a%b
 | ||||
| fn C.bignum_divmod(a &Number, b &Number, c &Number, d &Number) | ||||
| 
 | ||||
| // c = a & b
 | ||||
| fn C.bignum_and(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a | b
 | ||||
| fn C.bignum_or(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // c = a xor b
 | ||||
| fn C.bignum_xor(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // b = a << nbits
 | ||||
| fn C.bignum_lshift(a &Number, b &Number, nbits int) | ||||
| 
 | ||||
| // b = a >> nbits
 | ||||
| fn C.bignum_rshift(a &Number, b &Number, nbits int) | ||||
| 
 | ||||
| fn C.bignum_cmp(a &Number, b &Number) int | ||||
| 
 | ||||
| fn C.bignum_is_zero(a &Number) int | ||||
| 
 | ||||
| // n++
 | ||||
| fn C.bignum_inc(n &Number) | ||||
| 
 | ||||
| // n--
 | ||||
| fn C.bignum_dec(n &Number) | ||||
| 
 | ||||
| // c = a ^ b
 | ||||
| fn C.bignum_pow(a &Number, b &Number, c &Number) | ||||
| 
 | ||||
| // b = integer_square_root_of(a)
 | ||||
| fn C.bignum_isqrt(a &Number, b &Number) | ||||
| 
 | ||||
| // copy src number to dst number
 | ||||
| fn C.bignum_assign(dst &Number, src &Number) | ||||
| 
 | ||||
| // new returns a bignum, initialized to 0
 | ||||
| pub fn new() Number { | ||||
| 	return Number{} | ||||
| } | ||||
| 
 | ||||
| // conversion actions to/from big numbers:
 | ||||
| // from_int converts an ordinary int number `i` to big.Number
 | ||||
| pub fn from_int(i int) Number { | ||||
| 	n := Number{} | ||||
| 	C.bignum_from_int(&n, i) | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| // from_u64 converts an ordinary u64 number `u` to big.Number
 | ||||
| pub fn from_u64(u u64) Number { | ||||
| 	n := Number{} | ||||
| 	C.bignum_from_int(&n, u) | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| // from_hex_string converts a hex string to big.Number
 | ||||
| pub fn from_hex_string(input string) Number { | ||||
| 	mut s := input.trim_prefix('0x') | ||||
| 	if s.len == 0 { | ||||
| 		s = '0' | ||||
| 	} | ||||
| 	padding := '0'.repeat((8 - s.len % 8) % 8) | ||||
| 	s = padding + s | ||||
| 	n := Number{} | ||||
| 	C.bignum_from_string(&n, &char(s.str), s.len) | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| // from_string converts a decimal string to big.Number
 | ||||
| pub fn from_string(input string) Number { | ||||
| 	mut n := from_int(0) | ||||
| 	for _, c in input { | ||||
| 		d := from_int(int(c - `0`)) | ||||
| 		n = (n * big.ten) + d | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| // from_bytes converts an array of bytes (little-endian) to a big.Number.
 | ||||
| // Higher precedence bytes are expected at lower indices in the array.
 | ||||
| pub fn from_bytes(input []byte) ?Number { | ||||
| 	if input.len > 128 { | ||||
| 		return error('input array too large. big.Number can only hold up to 1024 bit numbers') | ||||
| 	} | ||||
| 	// pad input
 | ||||
| 	mut padded_input := []byte{len: ((input.len + 3) & ~0x3) - input.len, cap: (input.len + 3) & ~0x3, init: 0x0} | ||||
| 	padded_input << input | ||||
| 	// combine every 4 bytes into a u32 and insert into n.array
 | ||||
| 	mut n := Number{} | ||||
| 	for i := 0; i < padded_input.len; i += 4 { | ||||
| 		x3 := u32(padded_input[i]) | ||||
| 		x2 := u32(padded_input[i + 1]) | ||||
| 		x1 := u32(padded_input[i + 2]) | ||||
| 		x0 := u32(padded_input[i + 3]) | ||||
| 		val := (x3 << 24) | (x2 << 16) | (x1 << 8) | x0 | ||||
| 		n.array[(padded_input.len - i) / 4 - 1] = val | ||||
| 	} | ||||
| 	return n | ||||
| } | ||||
| 
 | ||||
| // .int() converts (a small) big.Number `n` to an ordinary integer.
 | ||||
| pub fn (n &Number) int() int { | ||||
| 	r := C.bignum_to_int(n) | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| const ( | ||||
| 	ten = from_int(10) | ||||
| ) | ||||
| 
 | ||||
| // .str returns a decimal representation of the big unsigned integer number n.
 | ||||
| pub fn (n &Number) str() string { | ||||
| 	if n.is_zero() { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	mut digits := []byte{} | ||||
| 	mut x := n.clone() | ||||
| 
 | ||||
| 	for !x.is_zero() { | ||||
| 		// changes to reflect new api
 | ||||
| 		div, mod := divmod(&x, &big.ten) | ||||
| 		digits << byte(mod.int()) + `0` | ||||
| 		x = div | ||||
| 	} | ||||
| 	return digits.reverse().bytestr() | ||||
| } | ||||
| 
 | ||||
| // .hexstr returns a hexadecimal representation of the bignum `n`
 | ||||
| pub fn (n &Number) hexstr() string { | ||||
| 	mut buf := [8192]byte{} | ||||
| 	mut s := '' | ||||
| 	unsafe { | ||||
| 		bp := &buf[0] | ||||
| 		// NB: C.bignum_to_string(), returns the HEXADECIMAL representation of the bignum n
 | ||||
| 		C.bignum_to_string(n, &char(bp), 8192) | ||||
| 		s = tos_clone(bp) | ||||
| 	} | ||||
| 	if s.len == 0 { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	return s | ||||
| } | ||||
| 
 | ||||
| // //////////////////////////////////////////////////////////
 | ||||
| // overloaded ops for the numbers:
 | ||||
| pub fn (a &Number) + (b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_add(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) - (b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_sub(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) * (b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_mul(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) / (b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_div(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) % (b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_mod(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| // divmod returns a pair of quotient and remainder from div modulo operation
 | ||||
| // between two bignums `a` and `b`
 | ||||
| pub fn divmod(a &Number, b &Number) (Number, Number) { | ||||
| 	c := Number{} | ||||
| 	d := Number{} | ||||
| 	C.bignum_divmod(a, b, &c, &d) | ||||
| 	return c, d | ||||
| } | ||||
| 
 | ||||
| // //////////////////////////////////////////////////////////
 | ||||
| pub fn cmp(a &Number, b &Number) int { | ||||
| 	return C.bignum_cmp(a, b) | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) is_zero() bool { | ||||
| 	return C.bignum_is_zero(a) != 0 | ||||
| } | ||||
| 
 | ||||
| pub fn (mut a Number) inc() { | ||||
| 	C.bignum_inc(&a) | ||||
| } | ||||
| 
 | ||||
| pub fn (mut a Number) dec() { | ||||
| 	C.bignum_dec(&a) | ||||
| } | ||||
| 
 | ||||
| pub fn pow(a &Number, b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_pow(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) isqrt() Number { | ||||
| 	b := Number{} | ||||
| 	C.bignum_isqrt(a, &b) | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| // //////////////////////////////////////////////////////////
 | ||||
| pub fn b_and(a &Number, b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_and(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn b_or(a &Number, b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_or(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn b_xor(a &Number, b &Number) Number { | ||||
| 	c := Number{} | ||||
| 	C.bignum_xor(a, b, &c) | ||||
| 	return c | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) lshift(nbits int) Number { | ||||
| 	b := Number{} | ||||
| 	C.bignum_lshift(a, &b, nbits) | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) rshift(nbits int) Number { | ||||
| 	b := Number{} | ||||
| 	C.bignum_rshift(a, &b, nbits) | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| pub fn (a &Number) clone() Number { | ||||
| 	b := Number{} | ||||
| 	C.bignum_assign(&b, a) | ||||
| 	return b | ||||
| } | ||||
| 
 | ||||
| // //////////////////////////////////////////////////////////
 | ||||
| pub fn factorial(nn &Number) Number { | ||||
| 	mut n := nn.clone() | ||||
| 	mut a := nn.clone() | ||||
| 	n.dec() | ||||
| 	mut i := 1 | ||||
| 	for !n.is_zero() { | ||||
| 		res := a * n | ||||
| 		n.dec() | ||||
| 		a = res | ||||
| 		i++ | ||||
| 	} | ||||
| 	return a | ||||
| } | ||||
| 
 | ||||
| pub fn fact(n int) Number { | ||||
| 	return factorial(from_int(n)) | ||||
| } | ||||
| 
 | ||||
| // bytes returns an array of the bytes for the number `n`,
 | ||||
| // in little endian format, where .bytes()[0] is the least
 | ||||
| // significant byte. The result is NOT trimmed, and will contain 0s, even
 | ||||
| // after the significant bytes.
 | ||||
| // This method is faster than .bytes_trimmed(), but may be less convenient.
 | ||||
| // Example: assert big.from_int(1).bytes()[0] == byte(0x01)
 | ||||
| // Example: assert big.from_int(1024).bytes()[1] == byte(0x04)
 | ||||
| // Example: assert big.from_int(1048576).bytes()[2] == byte(0x10)
 | ||||
| pub fn (n &Number) bytes() []byte { | ||||
| 	mut res := []byte{len: 128, init: 0} | ||||
| 	unsafe { C.memcpy(res.data, n, 128) } | ||||
| 	return res | ||||
| } | ||||
| 
 | ||||
| // bytes_trimmed returns an array of the bytes for the number `n`,
 | ||||
| // in little endian format, where .bytes_trimmed()[0] is the least
 | ||||
| // significant byte. The result is trimmed, so that *the last* byte
 | ||||
| // of the result is also the the last meaningfull byte, != 0 .
 | ||||
| // Example: assert big.from_int(1).bytes_trimmed() == [byte(0x01)]
 | ||||
| // Example: assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04]
 | ||||
| // Example: assert big.from_int(1048576).bytes_trimmed() == [byte(0x00), 0x00, 0x10]
 | ||||
| pub fn (n &Number) bytes_trimmed() []byte { | ||||
| 	mut res := []byte{len: 128, init: 0} | ||||
| 	unsafe { C.memcpy(res.data, n, 128) } | ||||
| 	mut non_zero_idx := 127 | ||||
| 	for ; non_zero_idx >= 0; non_zero_idx-- { | ||||
| 		if res[non_zero_idx] != 0 { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	res.trim(non_zero_idx + 1) | ||||
| 	return res | ||||
| } | ||||
|  | @ -0,0 +1,16 @@ | |||
| module big | ||||
| 
 | ||||
| pub const ( | ||||
| 	zero_int = Integer{ | ||||
| 		digits: []u32{len: 0} | ||||
| 		signum: 0 | ||||
| 	} | ||||
| 	one_int = Integer{ | ||||
| 		digits: [u32(1)] | ||||
| 		signum: 1 | ||||
| 	} | ||||
| 	two_int = Integer{ | ||||
| 		digits: [u32(2)] | ||||
| 		signum: 1 | ||||
| 	} | ||||
| ) | ||||
|  | @ -1,181 +1,346 @@ | |||
| import math.big | ||||
| 
 | ||||
| fn test_new_big() { | ||||
| 	n := big.new() | ||||
| 	assert sizeof(big.Number) == 128 | ||||
| 	assert n.hexstr() == '0' | ||||
| fn test_integer_from_int() { | ||||
| 	assert big.integer_from_int(0).hex() == '0' | ||||
| 	assert big.integer_from_int(1).hex() == '1' | ||||
| 	assert big.integer_from_int(255).hex() == 'ff' | ||||
| 	assert big.integer_from_int(127).hex() == '7f' | ||||
| 	assert big.integer_from_int(1024).hex() == '400' | ||||
| 	assert big.integer_from_int(2147483647).hex() == '7fffffff' | ||||
| } | ||||
| 
 | ||||
| fn test_from_int() { | ||||
| 	assert big.from_int(255).hexstr() == 'ff' | ||||
| 	assert big.from_int(127).hexstr() == '7f' | ||||
| 	assert big.from_int(1024).hexstr() == '400' | ||||
| 	assert big.from_int(2147483647).hexstr() == '7fffffff' | ||||
| 	assert big.from_int(-1).hexstr() == 'ffffffffffffffff' | ||||
| fn test_integer_from_u64() { | ||||
| 	assert big.integer_from_u64(0).hex() == '0' | ||||
| 	assert big.integer_from_u64(1).hex() == '1' | ||||
| 	assert big.integer_from_u64(255).hex() == 'ff' | ||||
| 	assert big.integer_from_u64(127).hex() == '7f' | ||||
| 	assert big.integer_from_u64(1024).hex() == '400' | ||||
| 	assert big.integer_from_u64(4294967295).hex() == 'ffffffff' | ||||
| 	assert big.integer_from_u64(4398046511104).hex() == '40000000000' | ||||
| 	max_value := big.integer_from_u64(-1) | ||||
| 
 | ||||
| 	assert max_value.hex() == 'ffffffffffffffff' | ||||
| } | ||||
| 
 | ||||
| fn test_from_u64() { | ||||
| 	assert big.from_u64(255).hexstr() == 'ff' | ||||
| 	assert big.from_u64(127).hexstr() == '7f' | ||||
| 	assert big.from_u64(1024).hexstr() == '400' | ||||
| 	assert big.from_u64(4294967295).hexstr() == 'ffffffff' | ||||
| 	assert big.from_u64(4398046511104).hexstr() == '40000000000' | ||||
| 	assert big.from_u64(-1).hexstr() == 'ffffffffffffffff' | ||||
| } | ||||
| fn test_integer_from_bytes() { | ||||
| 	assert big.integer_from_bytes([]).hex() == '0' | ||||
| 	assert big.integer_from_bytes([byte(0)]).hex() == '0' | ||||
| 	assert big.integer_from_bytes([byte(0x13), 0x37]).hex() == '1337' | ||||
| 	assert big.integer_from_bytes([byte(0x13), 0x37, 0xca]).hex() == '1337ca' | ||||
| 	assert big.integer_from_bytes([byte(0x13), 0x37, 0xca, 0xfe]).hex() == '1337cafe' | ||||
| 	assert big.integer_from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba]).hex() == '1337cafeba' | ||||
| 	assert big.integer_from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe]).hex() == '1337cafebabe' | ||||
| 
 | ||||
| fn test_plus() { | ||||
| 	mut a := big.from_u64(2) | ||||
| 	b := big.from_u64(3) | ||||
| 	c := a + b | ||||
| 	assert c.hexstr() == '5' | ||||
| 	assert (big.from_u64(1024) + big.from_u64(1024)).hexstr() == '800' | ||||
| 	a += b | ||||
| 	assert a.hexstr() == '5' | ||||
| 	a.inc() | ||||
| 	assert a.hexstr() == '6' | ||||
| 	a.dec() | ||||
| 	a.dec() | ||||
| 	assert a.hexstr() == '4' | ||||
| } | ||||
| 
 | ||||
| fn test_minus() { | ||||
| 	a := big.from_u64(2) | ||||
| 	mut b := big.from_u64(3) | ||||
| 	c := b - a | ||||
| 	assert c.hexstr() == '1' | ||||
| 	e := big.from_u64(1024) | ||||
| 	ee := e - e | ||||
| 	assert ee.hexstr() == '0' | ||||
| 	b -= a | ||||
| 	assert b.hexstr() == '1' | ||||
| } | ||||
| 
 | ||||
| fn test_divide() { | ||||
| 	a := big.from_u64(2) | ||||
| 	mut b := big.from_u64(3) | ||||
| 	c := b / a | ||||
| 	assert c.hexstr() == '1' | ||||
| 	assert (b % a).hexstr() == '1' | ||||
| 	e := big.from_u64(1024) // dec(1024) == hex(0x400)
 | ||||
| 	ee := e / e | ||||
| 	assert ee.hexstr() == '1' | ||||
| 	assert (e / a).hexstr() == '200' | ||||
| 	assert (e / (a * a)).hexstr() == '100' | ||||
| 	b /= a | ||||
| 	assert b.hexstr() == '1' | ||||
| } | ||||
| 
 | ||||
| fn test_multiply() { | ||||
| 	mut a := big.from_u64(2) | ||||
| 	b := big.from_u64(3) | ||||
| 	c := b * a | ||||
| 	assert c.hexstr() == '6' | ||||
| 	e := big.from_u64(1024) | ||||
| 	e2 := e * e | ||||
| 	e4 := e2 * e2 | ||||
| 	e8 := e2 * e2 * e2 * e2 | ||||
| 	e9 := e8 + big.from_u64(1) | ||||
| 	d := ((e9 * e9) + b) * c | ||||
| 	assert e4.hexstr() == '10000000000' | ||||
| 	assert e8.hexstr() == '100000000000000000000' | ||||
| 	assert e9.hexstr() == '100000000000000000001' | ||||
| 	assert d.hexstr() == '60000000000000000000c00000000000000000018' | ||||
| 	a *= b | ||||
| 	assert a.hexstr() == '6' | ||||
| } | ||||
| 
 | ||||
| fn test_mod() { | ||||
| 	assert (big.from_u64(13) % big.from_u64(10)).int() == 3 | ||||
| 	assert (big.from_u64(13) % big.from_u64(9)).int() == 4 | ||||
| 	assert (big.from_u64(7) % big.from_u64(5)).int() == 2 | ||||
| } | ||||
| 
 | ||||
| fn test_divmod() { | ||||
| 	x, y := big.divmod(big.from_u64(13), big.from_u64(10)) | ||||
| 	assert x.int() == 1 | ||||
| 	assert y.int() == 3 | ||||
| 	p, q := big.divmod(big.from_u64(13), big.from_u64(9)) | ||||
| 	assert p.int() == 1 | ||||
| 	assert q.int() == 4 | ||||
| 	c, d := big.divmod(big.from_u64(7), big.from_u64(5)) | ||||
| 	assert c.int() == 1 | ||||
| 	assert d.int() == 2 | ||||
| } | ||||
| 
 | ||||
| fn test_from_str() { | ||||
| 	assert big.from_string('9870123').str() == '9870123' | ||||
| 	assert big.from_string('').str() == '0' | ||||
| 	assert big.from_string('0').str() == '0' | ||||
| 	assert big.from_string('1').str() == '1' | ||||
| 	for i := 1; i < 307; i += 61 { | ||||
| 		input := '9'.repeat(i) | ||||
| 		out := big.from_string(input).str() | ||||
| 		// eprintln('>> i: $i input: $input.str()')
 | ||||
| 		// eprintln('>> i: $i   out: $out.str()')
 | ||||
| 		assert input == out | ||||
| 	mut bytes := []byte{cap: 1024} | ||||
| 	mut expected := '' | ||||
| 	for i := 0; i < bytes.cap; i++ { | ||||
| 		bytes << byte(i) | ||||
| 		expected = expected + byte(i).hex() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn test_from_hex_str() { | ||||
| 	assert big.from_hex_string('0x123').hexstr() == '123' | ||||
| 	for i in 1 .. 33 { | ||||
| 		input := 'e'.repeat(i) | ||||
| 		out := big.from_hex_string(input).hexstr() | ||||
| 		assert input == out | ||||
| 	} | ||||
| 	assert big.from_string('0').hexstr() == '0' | ||||
| } | ||||
| 
 | ||||
| fn test_str() { | ||||
| 	assert big.from_u64(255).str() == '255' | ||||
| 	assert big.from_u64(127).str() == '127' | ||||
| 	assert big.from_u64(1024).str() == '1024' | ||||
| 	assert big.from_u64(4294967295).str() == '4294967295' | ||||
| 	assert big.from_u64(4398046511104).str() == '4398046511104' | ||||
| 	assert big.from_int(int(4294967295)).str() == '18446744073709551615' | ||||
| 	assert big.from_int(-1).str() == '18446744073709551615' | ||||
| 	assert big.from_hex_string('e'.repeat(80)).str() == '1993587900192849410235353592424915306962524220866209251950572167300738410728597846688097947807470' | ||||
| } | ||||
| 
 | ||||
| fn test_factorial() { | ||||
| 	f5 := big.factorial(big.from_u64(5)) | ||||
| 	assert f5.hexstr() == '78' | ||||
| 	f100 := big.factorial(big.from_u64(100)) | ||||
| 	assert f100.hexstr() == '1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000' | ||||
| } | ||||
| 
 | ||||
| fn trimbytes(n int, x []byte) []byte { | ||||
| 	mut res := x.clone() | ||||
| 	res.trim(n) | ||||
| 	return res | ||||
| 	assert big.integer_from_bytes(bytes).hex() == expected.trim_left('0') | ||||
| } | ||||
| 
 | ||||
| fn test_bytes() { | ||||
| 	assert big.from_int(0).bytes().len == 128 | ||||
| 	assert big.from_hex_string('e'.repeat(100)).bytes().len == 128 | ||||
| 	assert trimbytes(3, big.from_int(1).bytes()) == [byte(0x01), 0x00, 0x00] | ||||
| 	assert trimbytes(3, big.from_int(1024).bytes()) == [byte(0x00), 0x04, 0x00] | ||||
| 	assert trimbytes(3, big.from_int(1048576).bytes()) == [byte(0x00), 0x00, 0x10] | ||||
| 	result1, sign1 := big.integer_from_u64(0x1337cafebabe).bytes() | ||||
| 	assert result1 == [byte(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe] | ||||
| 	assert sign1 == 1 | ||||
| 
 | ||||
| 	mut bytes := []byte{cap: 1024} | ||||
| 	mut expected := '' | ||||
| 	for i := 0; i < bytes.cap; i++ { | ||||
| 		bytes << byte(i | 1) | ||||
| 		expected = expected + byte(i).hex() | ||||
| 	} | ||||
| 	result2, sign2 := big.integer_from_bytes(bytes).bytes() | ||||
| 	assert result2 == bytes | ||||
| 	assert sign2 == 1 | ||||
| } | ||||
| 
 | ||||
| fn test_bytes_trimmed() { | ||||
| 	assert big.from_int(0).bytes_trimmed().len == 0 | ||||
| 	assert big.from_hex_string('AB'.repeat(50)).bytes_trimmed().len == 50 | ||||
| 	assert big.from_int(1).bytes_trimmed() == [byte(0x01)] | ||||
| 	assert big.from_int(1024).bytes_trimmed() == [byte(0x00), 0x04] | ||||
| 	assert big.from_int(1048576).bytes_trimmed() == [byte(0x00), 0x00, 0x10] | ||||
| fn test_addition() { | ||||
| 	a := big.integer_from_int(2) | ||||
| 	b := big.integer_from_int(3) | ||||
| 	c := a + b | ||||
| 	assert c.hex() == '5' | ||||
| 
 | ||||
| 	assert (big.integer_from_int(1024) + big.integer_from_int(1024)).hex() == '800' | ||||
| 
 | ||||
| 	fib1 := big.integer_from_string('84885164052257330097714121751630835360966663883732297726369399') or { | ||||
| 		panic('Cannot read decimal') | ||||
| 	} | ||||
| 	fib2 := big.integer_from_string('137347080577163115432025771710279131845700275212767467264610201') or { | ||||
| 		panic('Cannot read decimal') | ||||
| 	} | ||||
| 	assert (fib1 + fib2).str() == '222232244629420445529739893461909967206666939096499764990979600' | ||||
| } | ||||
| 
 | ||||
| fn test_from_bytes() ? { | ||||
| 	assert big.from_bytes([]) ?.hexstr() == '0' | ||||
| 	assert big.from_bytes([byte(0x13)]) ?.hexstr() == '13' | ||||
| 	assert big.from_bytes([byte(0x13), 0x37]) ?.hexstr() == '1337' | ||||
| 	assert big.from_bytes([byte(0x13), 0x37, 0xca]) ?.hexstr() == '1337ca' | ||||
| 	assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe]) ?.hexstr() == '1337cafe' | ||||
| 	assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba]) ?.hexstr() == '1337cafeba' | ||||
| 	assert big.from_bytes([byte(0x13), 0x37, 0xca, 0xfe, 0xba, 0xbe]) ?.hexstr() == '1337cafebabe' | ||||
| 	assert big.from_bytes([]byte{len: 128, init: 0x0}) ?.hexstr() == '0' | ||||
| 	if x := big.from_bytes([]byte{len: 129, init: 0x0}) { | ||||
| 		return error('expected error, got $x') | ||||
| fn test_subtraction() { | ||||
| 	a := big.integer_from_int(2) | ||||
| 	b := big.integer_from_int(3) | ||||
| 	assert (a - b).hex() == '-1' | ||||
| 	assert (b - a).hex() == '1' | ||||
| 
 | ||||
| 	c := big.integer_from_int(1024) | ||||
| 	assert (c - c) == big.zero_int | ||||
| 
 | ||||
| 	assert big.integer_from_int(-37) - big.integer_from_int(-54) == big.integer_from_int(17) | ||||
| } | ||||
| 
 | ||||
| fn test_multiplication() { | ||||
| 	a := big.integer_from_int(2) | ||||
| 	b := big.integer_from_int(3) | ||||
| 	c := big.integer_from_int(6) | ||||
| 	assert a * b == c | ||||
| 	assert big.integer_from_int(-869) * big.integer_from_int(789) == big.integer_from_int(-685641) | ||||
| 	e := big.integer_from_u32(1024) | ||||
| 	e2 := e * e | ||||
| 	e4 := e2 * e2 | ||||
| 	e8 := e2 * e2 * e2 * e2 | ||||
| 	e9 := e8 + big.one_int | ||||
| 	d := ((e9 * e9) + b) * c | ||||
| 	assert e4.hex() == '10000000000' | ||||
| 	assert e8.hex() == '100000000000000000000' | ||||
| 	assert e9.hex() == '100000000000000000001' | ||||
| 	assert d.hex() == '60000000000000000000c00000000000000000018' | ||||
| } | ||||
| 
 | ||||
| fn test_division() { | ||||
| 	a := big.integer_from_u64(2) | ||||
| 	b := big.integer_from_u64(3) | ||||
| 	c := b / a | ||||
| 	assert c.hex() == '1' | ||||
| 	assert (b % a).hex() == '1' | ||||
| 	e := big.integer_from_u64(1024) // dec(1024) == hex(0x400)
 | ||||
| 	ee := e / e | ||||
| 	assert ee.hex() == '1' | ||||
| 	assert (e / a).hex() == '200' | ||||
| 	assert (e / (a * a)).hex() == '100' | ||||
| 
 | ||||
| 	assert (b / a).hex() == '1' | ||||
| } | ||||
| 
 | ||||
| fn test_mod() { | ||||
| 	assert (big.integer_from_u64(13) % big.integer_from_u64(10)).int() == 3 | ||||
| 	assert (big.integer_from_u64(13) % big.integer_from_u64(9)).int() == 4 | ||||
| 	assert (big.integer_from_u64(7) % big.integer_from_u64(5)).int() == 2 | ||||
| } | ||||
| 
 | ||||
| fn test_divmod() { | ||||
| 	x, y := big.integer_from_u64(13).div_mod(big.integer_from_u64(10)) | ||||
| 	assert x.int() == 1 | ||||
| 	assert y.int() == 3 | ||||
| 	p, q := big.integer_from_u64(13).div_mod(big.integer_from_u64(9)) | ||||
| 	assert p.int() == 1 | ||||
| 	assert q.int() == 4 | ||||
| 	c, d := big.integer_from_u64(7).div_mod(big.integer_from_u64(5)) | ||||
| 	assert c.int() == 1 | ||||
| 	assert d.int() == 2 | ||||
| 	x1 := big.integer_from_string('2103180314840157') or { panic('Cannot read decimal') } | ||||
| 	y1 := big.integer_from_string('1631403814113') or { panic('Cannot read decimal') } | ||||
| 	q0 := big.integer_from_int(1289) | ||||
| 	r0 := big.integer_from_string('300798448500') or { panic('Cannot read decimal') } | ||||
| 	q1, r1 := x1.div_mod(y1) | ||||
| 	assert q1 == q0 | ||||
| 	assert r1 == r0 | ||||
| 
 | ||||
| 	e := big.integer_from_string('21408410031413414147401') or { panic('Cannot read decimal') } | ||||
| 	f := big.integer_from_string('3130541314113413') or { panic('Cannot read decimal') } | ||||
| 	g, h := e.div_mod(f) | ||||
| 	assert g.str() == '6838564' | ||||
| 	assert h.str() == '2900204736088469' | ||||
| } | ||||
| 
 | ||||
| fn test_conversion() { | ||||
| 	ten := big.integer_from_int(10) | ||||
| 
 | ||||
| 	mut n := big.integer_from_u64(-1) | ||||
| 
 | ||||
| 	mut digits := []rune{} | ||||
| 	for n.signum != 0 { | ||||
| 		quot, rem := n.div_mod(ten) | ||||
| 		digits << rune(rem.int()) + `0` | ||||
| 		n = quot | ||||
| 	} | ||||
| 
 | ||||
| 	assert digits.reverse().string() == '18446744073709551615' | ||||
| } | ||||
| 
 | ||||
| fn test_integer_from_string() { | ||||
| 	a := big.integer_from_string('00000000') or { panic('Zero int test fails') } | ||||
| 	assert a == big.zero_int | ||||
| 	b := big.integer_from_radix('00', 4) or { panic('Zero int test fails') } | ||||
| 	assert b == big.zero_int | ||||
| 	assert a == b | ||||
| 
 | ||||
| 	string_values := ['0', '1', '0012', '1349173614', '+24', '-325'] | ||||
| 	int_values := [0, 1, 12, 1349173614, 24, -325] | ||||
| 	for index in 0 .. string_values.len { | ||||
| 		x := big.integer_from_string(string_values[index]) or { | ||||
| 			panic('Could not convert decimal string') | ||||
| 		} | ||||
| 		y := big.integer_from_int(int_values[index]) | ||||
| 		assert x == y | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn test_integer_from_powers_of_2() { | ||||
| 	assert (big.integer_from_radix('101010', 2) or { panic('Cannot read binary') }).int() == 42 | ||||
| 	assert (big.integer_from_radix('1010', 2) or { panic('Cannot read binary') }).int() == 10 | ||||
| 	assert (big.integer_from_radix('-0000101', 2) or { panic('Cannot read binary') }).int() == -5 | ||||
| 
 | ||||
| 	assert (big.integer_from_radix('CAFE', 16) or { panic('Cannot read hexadecimal') }).int() == 0xCAFE | ||||
| 	assert (big.integer_from_radix('DED', 16) or { panic('Cannot read hexadecimal') }).int() == 0xDED | ||||
| 	assert (big.integer_from_radix('-abcd', 16) or { panic('Cannot read hexadecimal') }).int() == -0xabcd | ||||
| } | ||||
| 
 | ||||
| fn test_from_and_to_hex() { | ||||
| 	assert (big.integer_from_radix('123', 16) or { panic('Cannot read hexadecimal') }).hex() == '123' | ||||
| 	for i in 1 .. 33 { | ||||
| 		input := 'e'.repeat(i) | ||||
| 		output := (big.integer_from_radix(input, 16) or { panic('Cannot read hexadecimal') }).hex() | ||||
| 		assert input == output | ||||
| 	} | ||||
| 	assert (big.integer_from_string('0') or { panic('Cannot read decimal') }).str() == '0' | ||||
| } | ||||
| 
 | ||||
| fn test_str() { | ||||
| 	assert big.integer_from_u64(255).str() == '255' | ||||
| 	assert big.integer_from_u64(127).str() == '127' | ||||
| 	assert big.integer_from_u64(1024).str() == '1024' | ||||
| 	assert big.integer_from_u64(4294967295).str() == '4294967295' | ||||
| 	assert big.integer_from_u64(4398046511104).str() == '4398046511104' | ||||
| 	assert big.integer_from_u64(-1).str() == '18446744073709551615' | ||||
| 	assert (big.integer_from_radix('e'.repeat(80), 16) or { panic('Cannot read hexadecimal') }).str() == '1993587900192849410235353592424915306962524220866209251950572167300738410728597846688097947807470' | ||||
| } | ||||
| 
 | ||||
| fn test_exponentiation() { | ||||
| 	a := big.integer_from_int(2) | ||||
| 	assert a.pow(0).int() == 1 | ||||
| 	assert a.pow(1).int() == 2 | ||||
| 	assert a.pow(5).int() == 32 | ||||
| 	assert a.pow(10).int() == 1024 | ||||
| 	assert a.pow(30).int() == 1073741824 | ||||
| 
 | ||||
| 	exp_array := [u32(5), 7, 234, 524, 291, 13051] | ||||
| 	for exp in exp_array { | ||||
| 		expected := '1' + '0'.repeat(int(exp)) | ||||
| 		actual := a.pow(exp) | ||||
| 		assert actual.binary_str() == expected | ||||
| 	} | ||||
| 
 | ||||
| 	result := '66325146064916587705822805477951823674769212922003325230500180789514487101799702287247301347816140714887582527826252837635296749781071351621748491469338347097923896026211183517655658952346069454893422558286798338709431368762851475568899541999504754550056265493269010870696623999709399529395247064542825851568385196637089440522882877102429945439977107582295420418108331098961838419917230847980056560488541780255425015021238743932289115066701337398107639567748102191005710201353615093246958907555634902309636451244444952203735074916066229982498598205421944122042066749035283837586883383420374291325389757869347147357807188516650352693616763867685354382631931356465247637321960345782811272139101785279798666504361229957479336436466489780129445016691164329417001378480690804715301830926348058624' | ||||
| 
 | ||||
| 	assert big.integer_from_int(324).pow(u32(315)).str() == result | ||||
| } | ||||
| 
 | ||||
| fn test_mod_exponentiation() { | ||||
| 	divisor := big.integer_from_int(632) | ||||
| 	assert big.integer_from_int(324).mod_pow(u32(315), divisor) == big.integer_from_int(512) | ||||
| 
 | ||||
| 	a := big.integer_from_int(65) | ||||
| 	b := big.integer_from_int(2790) | ||||
| 	div := big.integer_from_int(3233) | ||||
| 
 | ||||
| 	assert a.mod_pow(17, div) == b | ||||
| 	assert b.mod_pow(413, div) == a | ||||
| } | ||||
| 
 | ||||
| fn test_gcd() { | ||||
| 	assert big.integer_from_int(0).gcd(big.integer_from_int(0)) == big.zero_int | ||||
| 	assert big.integer_from_int(10).gcd(big.integer_from_int(0)) == big.integer_from_int(10) | ||||
| 	assert big.integer_from_int(0).gcd(big.integer_from_int(-18)) == big.integer_from_int(18) | ||||
| 	assert big.integer_from_int(51).gcd(big.integer_from_int(22)) == big.one_int | ||||
| 	assert big.integer_from_int(98).gcd(big.integer_from_int(56)) == big.integer_from_int(14) | ||||
| 	assert big.integer_from_int(98).gcd(big.integer_from_int(56)) == big.integer_from_int(14) | ||||
| 
 | ||||
| 	a := big.integer_from_string('67116917544110') or { panic('Could not read decimal') } | ||||
| 	b := big.integer_from_string('60943431483592') or { panic('Could not read decimal') } | ||||
| 	c := big.integer_from_string('6299482') or { panic('Could not read decimal') } | ||||
| 	assert a.gcd(b) == c | ||||
| } | ||||
| 
 | ||||
| fn test_factorial() { | ||||
| 	f5 := big.integer_from_u64(5).factorial() | ||||
| 	assert f5.hex() == '78' | ||||
| 	f100 := big.integer_from_u64(100).factorial() | ||||
| 	assert f100.hex() == '1b30964ec395dc24069528d54bbda40d16e966ef9a70eb21b5b2943a321cdf10391745570cca9420c6ecb3b72ed2ee8b02ea2735c61a000000000000000000000000' | ||||
| } | ||||
| 
 | ||||
| fn test_inc_and_dec() { | ||||
| 	mut a := big.integer_from_int(2) | ||||
| 	mut b := big.integer_from_int(3) | ||||
| 	mut c := big.integer_from_int(4) | ||||
| 
 | ||||
| 	a.inc() | ||||
| 	c.dec() | ||||
| 	assert a == b | ||||
| 	assert b == c | ||||
| } | ||||
| 
 | ||||
| fn test_lshift() { | ||||
| 	assert big.integer_from_int(45).lshift(2) == big.integer_from_int(45 * 4) | ||||
| 	assert big.integer_from_int(45).lshift(3) == big.integer_from_int(45 * 8) | ||||
| 	assert big.integer_from_int(45).lshift(4) == big.integer_from_int(45 * 16) | ||||
| 	assert big.integer_from_int(45).lshift(5) == big.integer_from_int(45 * 32) | ||||
| 	assert big.integer_from_u64(0xabcedabcde).lshift(20) == big.integer_from_u64(0xabcedabcde00000) | ||||
| 	assert big.integer_from_bytes([byte(1), 1, 1]).lshift(56) == big.integer_from_bytes([ | ||||
| 		byte(1), | ||||
| 		1, | ||||
| 		1, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 	]) | ||||
| } | ||||
| 
 | ||||
| fn test_rshift() { | ||||
| 	assert big.integer_from_int(45).rshift(3) == big.integer_from_int(5) | ||||
| 	assert big.integer_from_int(0x13374956).rshift(16) == big.integer_from_int(0x1337) | ||||
| 	assert big.integer_from_bytes([ | ||||
| 		byte(1), | ||||
| 		1, | ||||
| 		1, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 		0, | ||||
| 	]).rshift(56) == big.integer_from_bytes([byte(1), 1, 1]) | ||||
| } | ||||
| 
 | ||||
| fn test_isqrt() { | ||||
| 	for i in 0 .. 1000 { | ||||
| 		a := big.integer_from_int(i) | ||||
| 		b := big.integer_from_int(i * i) | ||||
| 		assert b.isqrt() == a | ||||
| 	} | ||||
| 	values := [ | ||||
| 		'314', | ||||
| 		'213149', | ||||
| 		'2198614', | ||||
| 		'318014', | ||||
| 		'1000000000', | ||||
| 		'1000131039410', | ||||
| 		'2148170394871039847019843349714981', | ||||
| 	] | ||||
| 	for value in values { | ||||
| 		a := big.integer_from_string(value) or { panic('Cannot read from decimal') } | ||||
| 		b := a * a | ||||
| 		assert b.isqrt() == a | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn test_bitwise_ops() { | ||||
| 	a := big.integer_from_int(1).lshift(512) | ||||
| 	b := a - big.one_int | ||||
| 	assert a.bitwise_and(b) == big.zero_int | ||||
| 	assert b.bitwise_xor(b) == big.zero_int | ||||
| 	assert b.bitwise_or(b) == b | ||||
| 	assert b.bitwise_and(b) == b | ||||
| 	assert b.bitwise_not() == big.zero_int | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,762 @@ | |||
| module big | ||||
| 
 | ||||
| import math.util | ||||
| import math.bits | ||||
| import strings | ||||
| import strconv | ||||
| 
 | ||||
| const ( | ||||
| 	digit_array = '0123456789abcdefghijklmnopqrstuvwxyz'.bytes() | ||||
| ) | ||||
| 
 | ||||
| // big.Integer
 | ||||
| // -----------
 | ||||
| // It has the following properties:
 | ||||
| // 1. Every "digit" is an integer in the range [0, 2^32).
 | ||||
| // 2. The signum can be one of three values: -1, 0, +1 for
 | ||||
| // 		negative, zero, and positive values, respectively.
 | ||||
| // 3. There should be no leading zeros in the digit array.
 | ||||
| // 4. The digits are stored in little endian format, that is,
 | ||||
| //		the digits with a lower positional value (towards the right
 | ||||
| //		when represented as a string) have a lower index, and vice versa.
 | ||||
| pub struct Integer { | ||||
| 	digits []u32 | ||||
| pub: | ||||
| 	signum int | ||||
| } | ||||
| 
 | ||||
| fn int_signum(value int) int { | ||||
| 	if value == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	return if value < 0 { -1 } else { 1 } | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_int(value int) Integer { | ||||
| 	if value == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 	return Integer{ | ||||
| 		digits: [u32(util.iabs(value))] | ||||
| 		signum: int_signum(value) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_u32(value u32) Integer { | ||||
| 	if value == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 	return Integer{ | ||||
| 		digits: [value] | ||||
| 		signum: 1 | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_i64(value i64) Integer { | ||||
| 	if value == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 
 | ||||
| 	signum_value := if value < 0 { -1 } else { 1 } | ||||
| 	abs_value := u64(value * signum_value) | ||||
| 
 | ||||
| 	lower := u32(abs_value) | ||||
| 	upper := u32(abs_value >> 32) | ||||
| 
 | ||||
| 	if upper == 0 { | ||||
| 		return Integer{ | ||||
| 			digits: [lower] | ||||
| 			signum: signum_value | ||||
| 		} | ||||
| 	} else { | ||||
| 		return Integer{ | ||||
| 			digits: [lower, upper] | ||||
| 			signum: signum_value | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_u64(value u64) Integer { | ||||
| 	if value == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 
 | ||||
| 	lower := u32(value & 0x00000000ffffffff) | ||||
| 	upper := u32((value & 0xffffffff00000000) >> 32) | ||||
| 
 | ||||
| 	if upper == 0 { | ||||
| 		return Integer{ | ||||
| 			digits: [lower] | ||||
| 			signum: 1 | ||||
| 		} | ||||
| 	} else { | ||||
| 		return Integer{ | ||||
| 			digits: [lower, upper] | ||||
| 			signum: 1 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub struct IntegerConfig { | ||||
| 	signum int = 1 | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_bytes(input []byte, config IntegerConfig) Integer { | ||||
| 	// Thank you to Miccah (@mcastorina) for this implementation and relevant unit tests.
 | ||||
| 	if input.len == 0 { | ||||
| 		return integer_from_int(0) | ||||
| 	} | ||||
| 	// pad input
 | ||||
| 	mut padded_input := []byte{len: ((input.len + 3) & ~0x3) - input.len, cap: (input.len + 3) & ~0x3, init: 0x0} | ||||
| 	padded_input << input | ||||
| 	mut digits := []u32{len: padded_input.len / 4} | ||||
| 	// combine every 4 bytes into a u32 and insert into n.digits
 | ||||
| 	for i := 0; i < padded_input.len; i += 4 { | ||||
| 		x3 := u32(padded_input[i]) | ||||
| 		x2 := u32(padded_input[i + 1]) | ||||
| 		x1 := u32(padded_input[i + 2]) | ||||
| 		x0 := u32(padded_input[i + 3]) | ||||
| 		val := (x3 << 24) | (x2 << 16) | (x1 << 8) | x0 | ||||
| 		digits[(padded_input.len - i) / 4 - 1] = val | ||||
| 	} | ||||
| 	return Integer{ | ||||
| 		digits: digits | ||||
| 		signum: config.signum | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_string(characters string) ?Integer { | ||||
| 	return integer_from_radix(characters, 10) | ||||
| } | ||||
| 
 | ||||
| pub fn integer_from_radix(all_characters string, radix u32) ?Integer { | ||||
| 	if radix < 2 || radix > 36 { | ||||
| 		return error('Radix must be between 2 and 36 (inclusive)') | ||||
| 	} | ||||
| 	characters := all_characters.to_lower() | ||||
| 	validate_string(characters, radix) ? | ||||
| 	return match radix { | ||||
| 		2 { | ||||
| 			integer_from_special_string(characters, 1) | ||||
| 		} | ||||
| 		16 { | ||||
| 			integer_from_special_string(characters, 4) | ||||
| 		} | ||||
| 		else { | ||||
| 			integer_from_regular_string(characters, radix) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn validate_string(characters string, radix u32) ? { | ||||
| 	sign_present := characters[0] == `+` || characters[0] == `-` | ||||
| 
 | ||||
| 	start_index := if sign_present { 1 } else { 0 } | ||||
| 
 | ||||
| 	for index := start_index; index < characters.len; index++ { | ||||
| 		digit := characters[index] | ||||
| 		value := big.digit_array.index(digit) | ||||
| 
 | ||||
| 		if value == -1 { | ||||
| 			return error('Invalid character $digit') | ||||
| 		} | ||||
| 		if value >= radix { | ||||
| 			return error('Invalid character $digit for base $radix') | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn integer_from_special_string(characters string, chunk_size int) Integer { | ||||
| 	sign_present := characters[0] == `+` || characters[0] == `-` | ||||
| 
 | ||||
| 	signum := if sign_present { | ||||
| 		if characters[0] == `-` { -1 } else { 1 } | ||||
| 	} else { | ||||
| 		1 | ||||
| 	} | ||||
| 
 | ||||
| 	start_index := if sign_present { 1 } else { 0 } | ||||
| 
 | ||||
| 	mut big_digits := []u32{cap: ((characters.len * chunk_size) >> 5) + 1} | ||||
| 	mut current := u32(0) | ||||
| 	mut offset := 0 | ||||
| 	for index := characters.len - 1; index >= start_index; index-- { | ||||
| 		digit := characters[index] | ||||
| 		value := u32(big.digit_array.index(digit)) | ||||
| 
 | ||||
| 		current |= value << offset | ||||
| 		offset += chunk_size | ||||
| 
 | ||||
| 		if offset == 32 { | ||||
| 			big_digits << current | ||||
| 			current = u32(0) | ||||
| 			offset = 0 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Store the accumulated value into the digit array
 | ||||
| 	if current != 0 { | ||||
| 		big_digits << current | ||||
| 	} | ||||
| 
 | ||||
| 	for big_digits.len > 0 && big_digits.last() == 0 { | ||||
| 		big_digits.delete_last() | ||||
| 	} | ||||
| 
 | ||||
| 	return Integer{ | ||||
| 		digits: big_digits | ||||
| 		signum: if big_digits.len == 0 { 0 } else { signum } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn integer_from_regular_string(characters string, radix u32) Integer { | ||||
| 	sign_present := characters[0] == `+` || characters[0] == `-` | ||||
| 
 | ||||
| 	signum := if sign_present { | ||||
| 		if characters[0] == `-` { -1 } else { 1 } | ||||
| 	} else { | ||||
| 		1 | ||||
| 	} | ||||
| 
 | ||||
| 	start_index := if sign_present { 1 } else { 0 } | ||||
| 
 | ||||
| 	mut result := zero_int | ||||
| 	radix_int := integer_from_u32(radix) | ||||
| 
 | ||||
| 	for index := start_index; index < characters.len; index++ { | ||||
| 		digit := characters[index] | ||||
| 		value := big.digit_array.index(digit) | ||||
| 
 | ||||
| 		result *= radix_int | ||||
| 		result += integer_from_int(value) | ||||
| 	} | ||||
| 
 | ||||
| 	return Integer{ | ||||
| 		...result | ||||
| 		signum: result.signum * signum | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) abs() Integer { | ||||
| 	return if integer.signum == 0 { | ||||
| 		zero_int | ||||
| 	} else { | ||||
| 		Integer{ | ||||
| 			...integer | ||||
| 			signum: 1 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) neg() Integer { | ||||
| 	return if integer.signum == 0 { | ||||
| 		zero_int | ||||
| 	} else { | ||||
| 		Integer{ | ||||
| 			...integer | ||||
| 			signum: -integer.signum | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) + (addend Integer) Integer { | ||||
| 	// Quick exits
 | ||||
| 	if integer.signum == 0 { | ||||
| 		return addend | ||||
| 	} | ||||
| 	if addend.signum == 0 { | ||||
| 		return integer | ||||
| 	} | ||||
| 	// Non-zero cases
 | ||||
| 	return if integer.signum == addend.signum { | ||||
| 		integer.add(addend) | ||||
| 	} else { // Unequal signs
 | ||||
| 		integer.subtract(addend) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) - (subtrahend Integer) Integer { | ||||
| 	// Quick exits
 | ||||
| 	if integer.signum == 0 { | ||||
| 		return subtrahend.neg() | ||||
| 	} | ||||
| 	if subtrahend.signum == 0 { | ||||
| 		return integer | ||||
| 	} | ||||
| 	// Non-zero cases
 | ||||
| 	return if integer.signum == subtrahend.signum { | ||||
| 		integer.subtract(subtrahend) | ||||
| 	} else { | ||||
| 		integer.add(subtrahend) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (integer Integer) add(addend Integer) Integer { | ||||
| 	a := integer.digits | ||||
| 	b := addend.digits | ||||
| 	mut storage := []u32{len: util.imax(a.len, b.len) + 1} | ||||
| 	add_digit_array(a, b, mut storage) | ||||
| 	return Integer{ | ||||
| 		...integer | ||||
| 		digits: storage | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (integer Integer) subtract(subtrahend Integer) Integer { | ||||
| 	cmp := integer.abs_cmp(subtrahend) | ||||
| 	if cmp == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 	a, b := if cmp > 0 { integer, subtrahend } else { subtrahend, integer } | ||||
| 	mut storage := []u32{len: a.digits.len} | ||||
| 	subtract_digit_array(a.digits, b.digits, mut storage) | ||||
| 	return Integer{ | ||||
| 		signum: cmp * a.signum | ||||
| 		digits: storage | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) * (multiplicand Integer) Integer { | ||||
| 	// Quick exits
 | ||||
| 	if integer.signum == 0 || multiplicand.signum == 0 { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 	if integer == one_int { | ||||
| 		return multiplicand | ||||
| 	} | ||||
| 	if multiplicand == one_int { | ||||
| 		return integer | ||||
| 	} | ||||
| 	// The final sign is the product of the signs
 | ||||
| 	mut storage := []u32{len: integer.digits.len + multiplicand.digits.len} | ||||
| 	multiply_digit_array(integer.digits, multiplicand.digits, mut storage) | ||||
| 	return Integer{ | ||||
| 		signum: integer.signum * multiplicand.signum | ||||
| 		digits: storage | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) div_mod(divisor Integer) (Integer, Integer) { | ||||
| 	// Quick exits
 | ||||
| 	if divisor.signum == 0 { | ||||
| 		panic('Cannot divide by zero') | ||||
| 	} | ||||
| 	if integer.signum == 0 { | ||||
| 		return zero_int, zero_int | ||||
| 	} | ||||
| 	if divisor == one_int { | ||||
| 		return integer, zero_int | ||||
| 	} | ||||
| 	if divisor.signum == -1 { | ||||
| 		q, r := integer.div_mod(divisor.neg()) | ||||
| 		return q.neg(), r | ||||
| 	} | ||||
| 	if integer.signum == -1 { | ||||
| 		q, r := integer.neg().div_mod(divisor) | ||||
| 		if r.signum == 0 { | ||||
| 			return q.neg(), zero_int | ||||
| 		} else { | ||||
| 			return q.neg() - one_int, divisor - r | ||||
| 		} | ||||
| 	} | ||||
| 	// Division for positive integers
 | ||||
| 	mut q := []u32{cap: integer.digits.len - divisor.digits.len + 1} | ||||
| 	mut r := []u32{cap: integer.digits.len} | ||||
| 	divide_digit_array(integer.digits, divisor.digits, mut q, mut r) | ||||
| 	quotient := Integer{ | ||||
| 		signum: if q.len == 0 { 0 } else { 1 } | ||||
| 		digits: q | ||||
| 	} | ||||
| 	remainder := Integer{ | ||||
| 		signum: if r.len == 0 { 0 } else { 1 } | ||||
| 		digits: r | ||||
| 	} | ||||
| 	return quotient, remainder | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) / (b Integer) Integer { | ||||
| 	q, _ := a.div_mod(b) | ||||
| 	return q | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) % (b Integer) Integer { | ||||
| 	_, r := a.div_mod(b) | ||||
| 	return r | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) pow(exponent u32) Integer { | ||||
| 	if exponent == 0 { | ||||
| 		return one_int | ||||
| 	} | ||||
| 	if exponent == 1 { | ||||
| 		return a | ||||
| 	} | ||||
| 	mut n := exponent | ||||
| 	mut x := a | ||||
| 	mut y := one_int | ||||
| 	for n > 1 { | ||||
| 		if n & 1 == 1 { | ||||
| 			y *= x | ||||
| 		} | ||||
| 		x *= x | ||||
| 		n >>= 1 | ||||
| 	} | ||||
| 	return x * y | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) mod_pow(exponent u32, divisor Integer) Integer { | ||||
| 	if exponent == 0 { | ||||
| 		return one_int | ||||
| 	} | ||||
| 	if exponent == 1 { | ||||
| 		return a % divisor | ||||
| 	} | ||||
| 	mut n := exponent | ||||
| 	mut x := a % divisor | ||||
| 	mut y := one_int | ||||
| 	for n > 1 { | ||||
| 		if n & 1 == 1 { | ||||
| 			y *= x % divisor | ||||
| 		} | ||||
| 		x *= x % divisor | ||||
| 		n >>= 1 | ||||
| 	} | ||||
| 	return x * y % divisor | ||||
| } | ||||
| 
 | ||||
| pub fn (mut a Integer) inc() { | ||||
| 	a = a + one_int | ||||
| } | ||||
| 
 | ||||
| pub fn (mut a Integer) dec() { | ||||
| 	a = a - one_int | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) == (b Integer) bool { | ||||
| 	return a.signum == b.signum && a.digits.len == b.digits.len && a.digits == b.digits | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) abs_cmp(b Integer) int { | ||||
| 	return compare_digit_array(a.digits, b.digits) | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) < (b Integer) bool { | ||||
| 	// Quick exits based on signum value:
 | ||||
| 	if a.signum < b.signum { | ||||
| 		return true | ||||
| 	} | ||||
| 	if a.signum > b.signum { | ||||
| 		return false | ||||
| 	} | ||||
| 	// They have equal sign
 | ||||
| 	signum := a.signum | ||||
| 	if signum == 0 { // Are they both zero?
 | ||||
| 		return false | ||||
| 	} | ||||
| 	// If they are negative, the one with the larger absolute value is smaller
 | ||||
| 	cmp := a.abs_cmp() | ||||
| 	return if signum < 0 { cmp > 0 } else { cmp < 0 } | ||||
| } | ||||
| 
 | ||||
| fn check_sign(a Integer) { | ||||
| 	if a.signum < 0 { | ||||
| 		panic('Bitwise operations are only supported for nonnegative integers') | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) bitwise_or(b Integer) Integer { | ||||
| 	check_sign(a) | ||||
| 	check_sign(b) | ||||
| 	mut result := []u32{len: util.imax(a.digits.len, b.digits.len), init: 0} | ||||
| 	bitwise_or_digit_array(a.digits, b.digits, mut result) | ||||
| 	return Integer{ | ||||
| 		digits: result | ||||
| 		signum: if result.len == 0 { 0 } else { 1 } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) bitwise_and(b Integer) Integer { | ||||
| 	check_sign(a) | ||||
| 	check_sign(b) | ||||
| 	mut result := []u32{len: util.imax(a.digits.len, b.digits.len), init: 0} | ||||
| 	bitwise_and_digit_array(a.digits, b.digits, mut result) | ||||
| 	return Integer{ | ||||
| 		digits: result | ||||
| 		signum: if result.len == 0 { 0 } else { 1 } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) bitwise_not() Integer { | ||||
| 	check_sign(a) | ||||
| 	mut result := []u32{len: a.digits.len, init: 0} | ||||
| 	bitwise_not_digit_array(a.digits, mut result) | ||||
| 	return Integer{ | ||||
| 		digits: result | ||||
| 		signum: if result.len == 0 { 0 } else { 1 } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) bitwise_xor(b Integer) Integer { | ||||
| 	check_sign(a) | ||||
| 	check_sign(b) | ||||
| 	mut result := []u32{len: util.imax(a.digits.len, b.digits.len), init: 0} | ||||
| 	bitwise_xor_digit_array(a.digits, b.digits, mut result) | ||||
| 	return Integer{ | ||||
| 		digits: result | ||||
| 		signum: if result.len == 0 { 0 } else { 1 } | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) lshift(amount u32) Integer { | ||||
| 	if a.signum == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	if amount == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	normalised_amount := amount & 31 | ||||
| 	digit_offset := int(amount >> 5) | ||||
| 	mut new_array := []u32{len: a.digits.len + digit_offset, init: 0} | ||||
| 	for index in 0 .. a.digits.len { | ||||
| 		new_array[index + digit_offset] = a.digits[index] | ||||
| 	} | ||||
| 	if normalised_amount > 0 { | ||||
| 		shift_digits_left(new_array, normalised_amount, mut new_array) | ||||
| 	} | ||||
| 	return Integer{ | ||||
| 		digits: new_array | ||||
| 		signum: a.signum | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) rshift(amount u32) Integer { | ||||
| 	if a.signum == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	if amount == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	normalised_amount := amount & 31 | ||||
| 	digit_offset := int(amount >> 5) | ||||
| 	if digit_offset >= a.digits.len { | ||||
| 		return zero_int | ||||
| 	} | ||||
| 	mut new_array := []u32{len: a.digits.len - digit_offset, init: 0} | ||||
| 	for index in 0 .. new_array.len { | ||||
| 		new_array[index] = a.digits[index + digit_offset] | ||||
| 	} | ||||
| 	if normalised_amount > 0 { | ||||
| 		shift_digits_right(new_array, normalised_amount, mut new_array) | ||||
| 	} | ||||
| 	return Integer{ | ||||
| 		digits: new_array | ||||
| 		signum: a.signum | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) binary_str() string { | ||||
| 	// We have the zero integer
 | ||||
| 	if integer.signum == 0 { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	// Add the sign if present
 | ||||
| 	sign_needed := integer.signum == -1 | ||||
| 	mut result_builder := strings.new_builder(integer.digits.len * 32 + | ||||
| 		if sign_needed { 1 } else { 0 }) | ||||
| 	if sign_needed { | ||||
| 		result_builder.write_string('-') | ||||
| 	} | ||||
| 
 | ||||
| 	result_builder.write_string(u32_to_binary_without_lz(integer.digits[integer.digits.len - 1])) | ||||
| 
 | ||||
| 	for index := integer.digits.len - 2; index >= 0; index-- { | ||||
| 		result_builder.write_string(u32_to_binary_with_lz(integer.digits[index])) | ||||
| 	} | ||||
| 	return result_builder.str() | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) hex() string { | ||||
| 	// We have the zero integer
 | ||||
| 	if integer.signum == 0 { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	// Add the sign if present
 | ||||
| 	sign_needed := integer.signum == -1 | ||||
| 	mut result_builder := strings.new_builder(integer.digits.len * 8 + | ||||
| 		if sign_needed { 1 } else { 0 }) | ||||
| 	if sign_needed { | ||||
| 		result_builder.write_string('-') | ||||
| 	} | ||||
| 
 | ||||
| 	result_builder.write_string(u32_to_hex_without_lz(integer.digits[integer.digits.len - 1])) | ||||
| 
 | ||||
| 	for index := integer.digits.len - 2; index >= 0; index-- { | ||||
| 		result_builder.write_string(u32_to_hex_with_lz(integer.digits[index])) | ||||
| 	} | ||||
| 	return result_builder.str() | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) radix_str(radix u32) string { | ||||
| 	if integer.signum == 0 { | ||||
| 		return '0' | ||||
| 	} | ||||
| 	return match radix { | ||||
| 		2 { | ||||
| 			integer.binary_str() | ||||
| 		} | ||||
| 		16 { | ||||
| 			integer.hex() | ||||
| 		} | ||||
| 		else { | ||||
| 			integer.general_radix_str(radix) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| fn (integer Integer) general_radix_str(radix u32) string { | ||||
| 	divisor := integer_from_u32(radix) | ||||
| 	mut rune_array := []rune{} | ||||
| 
 | ||||
| 	mut current := integer.abs() | ||||
| 	mut digit := zero_int | ||||
| 	for current.signum > 0 { | ||||
| 		current, digit = current.div_mod(divisor) | ||||
| 		rune_array << big.digit_array[digit.int()] | ||||
| 	} | ||||
| 	if integer.signum == -1 { | ||||
| 		rune_array << `-` | ||||
| 	} | ||||
| 
 | ||||
| 	rune_array.reverse_in_place() | ||||
| 	return rune_array.string() | ||||
| } | ||||
| 
 | ||||
| pub fn (integer Integer) str() string { | ||||
| 	return integer.radix_str(10) | ||||
| } | ||||
| 
 | ||||
| fn u32_to_binary_without_lz(value u32) string { | ||||
| 	return strconv.format_uint(value, 2) | ||||
| } | ||||
| 
 | ||||
| fn u32_to_binary_with_lz(value u32) string { | ||||
| 	mut result_builder := strings.new_builder(32) | ||||
| 	binary_result := strconv.format_uint(value, 2) | ||||
| 
 | ||||
| 	result_builder.write_string(strings.repeat(`0`, 32 - binary_result.len)) | ||||
| 	result_builder.write_string(binary_result) | ||||
| 
 | ||||
| 	return result_builder.str() | ||||
| } | ||||
| 
 | ||||
| fn u32_to_hex_without_lz(value u32) string { | ||||
| 	return strconv.format_uint(value, 16) | ||||
| } | ||||
| 
 | ||||
| fn u32_to_hex_with_lz(value u32) string { | ||||
| 	mut result_builder := strings.new_builder(8) | ||||
| 	hex_result := strconv.format_uint(value, 16) | ||||
| 
 | ||||
| 	result_builder.write_string(strings.repeat(`0`, 8 - hex_result.len)) | ||||
| 	result_builder.write_string(hex_result) | ||||
| 
 | ||||
| 	return result_builder.str() | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) int() int { | ||||
| 	if a.signum == 0 { | ||||
| 		return 0 | ||||
| 	} | ||||
| 	value := int(a.digits[0] & 0x7fffffff) | ||||
| 	return value * a.signum | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) bytes() ([]byte, int) { | ||||
| 	if a.signum == 0 { | ||||
| 		return []byte{len: 0}, 0 | ||||
| 	} | ||||
| 	mut result := []byte{cap: a.digits.len * 4} | ||||
| 	mut mask := u32(0xff000000) | ||||
| 	mut offset := 24 | ||||
| 	mut non_zero_found := false | ||||
| 	for index := a.digits.len - 1; index >= 0; { | ||||
| 		value := byte((a.digits[index] & mask) >> offset) | ||||
| 		non_zero_found = non_zero_found || value != 0 | ||||
| 		if non_zero_found { | ||||
| 			result << value | ||||
| 		} | ||||
| 		mask >>= 8 | ||||
| 		offset -= 8 | ||||
| 		if offset < 0 { | ||||
| 			mask = u32(0xff000000) | ||||
| 			offset = 24 | ||||
| 			index-- | ||||
| 		} | ||||
| 	} | ||||
| 	return result, a.signum | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) gcd(b Integer) Integer { | ||||
| 	if a.signum == 0 { | ||||
| 		return b.abs() | ||||
| 	} | ||||
| 	if b.signum == 0 { | ||||
| 		return a.abs() | ||||
| 	} | ||||
| 	if a.signum < 0 { | ||||
| 		return a.neg().gcd(b) | ||||
| 	} | ||||
| 	if b.signum < 0 { | ||||
| 		return a.gcd(b.neg()) | ||||
| 	} | ||||
| 	mut x := a | ||||
| 	mut y := b | ||||
| 	mut r := x % y | ||||
| 	for r.signum != 0 { | ||||
| 		x = y | ||||
| 		y = r | ||||
| 		r = x % y | ||||
| 	} | ||||
| 	return y | ||||
| } | ||||
| 
 | ||||
| pub fn (a Integer) factorial() Integer { | ||||
| 	if a.signum == 0 { | ||||
| 		return one_int | ||||
| 	} | ||||
| 	mut product := one_int | ||||
| 	mut current := a | ||||
| 	for current.signum != 0 { | ||||
| 		product *= current | ||||
| 		current.dec() | ||||
| 	} | ||||
| 	return product | ||||
| } | ||||
| 
 | ||||
| // isqrt returns the closest integer square root of the given integer.
 | ||||
| pub fn (a Integer) isqrt() Integer { | ||||
| 	if a.signum < 0 { | ||||
| 		panic('Cannot obtain square root of negative integer') | ||||
| 	} | ||||
| 	if a.signum == 0 { | ||||
| 		return a | ||||
| 	} | ||||
| 	if a.digits.len == 1 && a.digits.last() == 1 { | ||||
| 		return a | ||||
| 	} | ||||
| 
 | ||||
| 	mut shift := a.digits.len * 32 - bits.leading_zeros_32(a.digits.last()) | ||||
| 	if shift & 1 == 1 { | ||||
| 		shift += 1 | ||||
| 	} | ||||
| 	mut result := zero_int | ||||
| 	for shift >= 0 { | ||||
| 		result = result.lshift(1) | ||||
| 		larger := result + one_int | ||||
| 		if (larger * larger).abs_cmp(a.rshift(u32(shift))) <= 0 { | ||||
| 			result = larger | ||||
| 		} | ||||
| 		shift -= 2 | ||||
| 	} | ||||
| 	return result | ||||
| } | ||||
		Loading…
	
		Reference in New Issue