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:
379
vlib/math/big/array_ops.v
Normal file
379
vlib/math/big/array_ops.v
Normal 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()
|
||||
}
|
||||
}
|
221
vlib/math/big/array_ops_test.v
Normal file
221
vlib/math/big/array_ops_test.v
Normal 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]
|
||||
}
|
@@ -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
16
vlib/math/big/big.v
Normal 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
|
||||
}
|
||||
)
|
@@ -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
762
vlib/math/big/integer.v
Normal 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
|
||||
}
|
Reference in New Issue
Block a user