math.big: implement big.integer in V (#11352)

pull/11356/head
Subhomoy Haldar 2021-08-31 21:51:00 +05:30 committed by GitHub
parent f8aaf4bf67
commit dadfda9400
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1707 additions and 1297 deletions

View File

@ -1,2 +0,0 @@
This folder contains bn.h and bn.c files
from https://github.com/kokke/tiny-bignum-c

664
thirdparty/bignum/bn.c vendored
View File

@ -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(&current, 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(&current); // current <<= 1;
_lshift_one_bit(&denom); // denom <<= 1;
}
if (!overflow)
{
_rshift_one_bit(&denom); // denom >>= 1;
_rshift_one_bit(&current); // current >>= 1;
}
bignum_init(c); // int answer = 0;
while (!bignum_is_zero(&current)) // while (current != 0)
{
if (bignum_cmp(&tmp, &denom) != SMALLER) // if (dividend >= denom)
{
bignum_sub(&tmp, &denom, &tmp); // dividend -= denom;
bignum_or(c, &current, c); // answer |= current;
}
_rshift_one_bit(&current); // 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;
}

123
thirdparty/bignum/bn.h vendored
View File

@ -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__ */

View File

@ -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()
}
}

View File

@ -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]
}

View File

@ -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
}

View File

@ -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
}
)

View File

@ -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
}

View File

@ -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
}