1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

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

This commit is contained in:
Subhomoy Haldar
2021-08-31 21:51:00 +05:30
committed by GitHub
parent f8aaf4bf67
commit dadfda9400
9 changed files with 1707 additions and 1297 deletions

379
vlib/math/big/array_ops.v Normal file
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
}

16
vlib/math/big/big.v Normal file
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
}

762
vlib/math/big/integer.v Normal file
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
}