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