Initial project import

This commit is contained in:
Agila Forge Importer committed 2026-07-13 15:20:32 +00:00
commit 23f2d29e32
11957 files changed
+1754577

No files matched your search

+324
View File
@@ -0,0 +1,324 @@
module big
import math.bits
// 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).
@[direct_array_access]
fn compare_digit_array(operand_a []u64, operand_b []u64) 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
@[direct_array_access]
fn add_digit_array(operand_a []u64, operand_b []u64, mut sum []u64) {
// Zero length cases
if operand_a.len == 0 {
for index in 0 .. operand_b.len {
sum[index] = operand_b[index]
}
shrink_tail_zeros(mut sum)
return
}
if operand_b.len == 0 {
for index in 0 .. operand_a.len {
sum[index] = operand_a[index]
}
shrink_tail_zeros(mut sum)
return
}
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 .. b.len {
partial := carry + a[index] + b[index]
sum[index] = partial & max_digit
carry = partial >> digit_bits
}
for index in b.len .. a.len {
partial := carry + a[index]
sum[index] = partial & max_digit
carry = partial >> digit_bits
}
sum[a.len] = carry
shrink_tail_zeros(mut sum)
}
// 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 and is 0
@[direct_array_access]
fn subtract_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
// 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]
}
return
}
mut borrow := u64(0)
for index in 0 .. operand_b.len {
a := operand_a[index]
b := operand_b[index] + borrow
diff := a - b
borrow = (diff >> digit_bits) & 1
storage[index] = diff + (borrow << digit_bits)
}
for index in operand_b.len .. operand_a.len {
diff := operand_a[index] - borrow
borrow = (diff >> digit_bits) & 1
storage[index] = diff + (borrow << digit_bits)
}
shrink_tail_zeros(mut storage)
}
const karatsuba_multiplication_limit = 70
const toom3_multiplication_limit = 360
@[inline]
fn multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
max_len := if operand_a.len >= operand_b.len {
operand_a.len
} else {
operand_b.len
}
if max_len >= toom3_multiplication_limit {
toom3_multiply_digit_array(operand_a, operand_b, mut storage)
} else if max_len >= karatsuba_multiplication_limit {
karatsuba_multiply_digit_array(operand_a, operand_b, mut storage)
} else {
simple_multiply_digit_array(operand_a, operand_b, mut storage)
}
}
// 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.
@[direct_array_access]
fn simple_multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
for b_index in 0 .. operand_b.len {
mut hi := u64(0)
mut lo := u64(0)
for a_index in 0 .. operand_a.len {
hi, lo = bits.mul_add_64(operand_a[a_index], operand_b[b_index], storage[a_index +
b_index] + hi)
storage[a_index + b_index] = lo & max_digit
hi = (hi << (64 - digit_bits)) | (lo >> digit_bits)
}
if hi != 0 {
storage[b_index + operand_a.len] = hi
}
}
shrink_tail_zeros(mut storage)
}
// 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
@[direct_array_access]
fn multiply_array_by_digit(operand_a []u64, value u64, mut storage []u64) {
if value == 0 {
storage.clear()
return
}
if value == 1 {
for index in 0 .. operand_a.len {
storage[index] = operand_a[index]
}
shrink_tail_zeros(mut storage)
return
}
mut hi := u64(0)
mut lo := u64(0)
for index in 0 .. operand_a.len {
hi, lo = bits.mul_add_64(operand_a[index], value, hi)
storage[index] = lo & max_digit
hi = hi << (64 - digit_bits) + (lo >> digit_bits)
}
if hi > 0 {
storage[operand_a.len] = hi
}
shrink_tail_zeros(mut storage)
}
// 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
@[direct_array_access]
fn divide_digit_array(operand_a []u64, operand_b []u64, mut quotient []u64, mut remainder []u64) {
cmp_result := compare_digit_array(operand_a, operand_b)
// a == b => q, r = 1, 0
if cmp_result == 0 {
quotient[0] = 1
remainder.clear()
return
}
// a < b => q, r = 0, a
if cmp_result < 0 {
quotient.clear()
for i in 0 .. operand_a.len {
remainder[i] = operand_a[i]
}
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 without previous allocation
@[direct_array_access]
fn divide_array_by_digit(operand_a []u64, divisor u64, mut quotient []u64, mut remainder []u64) {
if operand_a.len == 1 {
// 1 digit for both dividend and divisor
dividend := operand_a[0]
q := dividend / divisor
quotient[0] = q
rem := dividend % divisor
remainder[0] = rem
shrink_tail_zeros(mut quotient)
shrink_tail_zeros(mut remainder)
return
}
// Dividend has more digits
mut rem := u64(0)
mut quo := u64(0)
// Perform division step by step
for index := operand_a.len - 1; index >= 0; index-- {
hi := rem >> (64 - digit_bits)
lo := rem << digit_bits | operand_a[index]
quo, rem = bits.div_64(hi, lo, divisor)
quotient[index] = quo & max_digit
}
// Remove leading zeros from quotient
shrink_tail_zeros(mut quotient)
remainder[0] = rem
shrink_tail_zeros(mut remainder)
}
@[inline]
fn divide_array_by_array(operand_a []u64, operand_b []u64, mut quotient []u64, mut remainder []u64) {
knuth_divide_array_by_array(operand_a, operand_b, mut quotient, mut remainder)
}
// 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 `digit_bits`. The storage is expected to
// allocated with zeroes.
@[direct_array_access]
fn shift_digits_left(original []u64, amount u32, mut storage []u64) {
mut leftover := u64(0)
offset := digit_bits - amount
for index in 0 .. original.len {
value := (leftover | (original[index] << amount)) & max_digit
leftover = (original[index] & (u64(-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 `digit_bits`. The storage is expected to
// be allocated with zeroes.
@[direct_array_access]
fn shift_digits_right(original []u64, amount u32, mut storage []u64) {
mut moveover := u64(0)
mask := (u64(1) << amount) - 1
offset := digit_bits - amount
for index := original.len - 1; index >= 0; index-- {
value := (moveover << offset) | (original[index] >> amount)
moveover = original[index] & mask
storage[index] = value
}
shrink_tail_zeros(mut storage)
}
@[direct_array_access]
fn bitwise_or_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
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]
}
shrink_tail_zeros(mut storage)
}
@[direct_array_access]
fn bitwise_and_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
lower := imin(operand_a.len, operand_b.len)
for index in 0 .. lower {
storage[index] = operand_a[index] & operand_b[index]
}
shrink_tail_zeros(mut storage)
}
@[direct_array_access]
fn bitwise_xor_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
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]
}
shrink_tail_zeros(mut storage)
}
@[direct_array_access]
fn bitwise_not_digit_array(original []u64, mut storage []u64) {
for index in 0 .. original.len {
storage[index] = (~original[index]) & max_digit
}
shrink_tail_zeros(mut storage)
}
+232
View File
@@ -0,0 +1,232 @@
// vtest build: !do_not_test ?
module big
fn test_add_digit_array_01() {
a := [u64(1), 1, 1]
b := [u64(1), 1, 1]
mut c := []u64{len: 4}
add_digit_array(a, b, mut c)
assert c == [u64(2), 2, 2]
}
fn test_add_digit_array_02() {
a := [u64(1), u64(1) << (digit_bits - 1), 1]
b := [u64(1), u64(1) << (digit_bits - 1), 1]
mut c := []u64{len: 4}
add_digit_array(a, b, mut c)
assert c == [u64(2), 0, 3]
}
fn test_add_digit_array_03() {
a := [u64(1), (u64(1) << (digit_bits - 1)) + u64(34), 1]
b := [u64(242), u64(1) << (digit_bits - 1), 1]
mut c := []u64{len: 4}
add_digit_array(a, b, mut c)
assert c == [u64(243), 34, 3]
}
fn test_add_digit_array_04() {
a := [u64(0)]
b := [u64(1), 3, 4]
mut c := []u64{len: 4}
add_digit_array(a, b, mut c)
assert c == [u64(1), 3, 4]
}
fn test_add_digit_array_05() {
a := [u64(1), 3, 4]
b := [u64(0)]
mut c := []u64{len: 4}
add_digit_array(a, b, mut c)
assert c == [u64(1), 3, 4]
}
fn test_add_digit_array_06() {
a := [u64(46), 13, 462, 13]
b := [u64(1), 3, 4]
mut c := []u64{len: 5}
add_digit_array(a, b, mut c)
assert c == [u64(47), 16, 466, 13]
}
fn test_subtract_digit_array_01() {
a := [u64(2), 2, 2, 2, 2]
b := [u64(1), 1, 2, 1, 1]
mut c := []u64{len: a.len}
subtract_digit_array(a, b, mut c)
assert c == [u64(1), 1, 0, 1, 1]
}
fn test_subtract_digit_array_02() {
a := [u64(0), 0, 0, 0, 1]
b := [u64(0), 0, 1]
mut c := []u64{len: a.len}
subtract_digit_array(a, b, mut c)
assert c == [u64(0), 0, u64(-1) & max_digit, u64(-1) & max_digit]
}
fn test_subtract_digit_array_03() {
a := [u64(0), 0, 0, 0, 1, 13]
b := [u64(0), 0, 1]
mut c := []u64{len: a.len}
subtract_digit_array(a, b, mut c)
assert c == [u64(0), 0, u64(-1) & max_digit, u64(-1) & max_digit, 0, 13]
}
fn test_subtract_digit_array_04() {
a := [u64(0x2), 0x4, 0x5, 0x3]
b := [u64(0x0), 0x0, 0x5, 0x3]
mut c := []u64{len: a.len}
subtract_digit_array(a, b, mut c)
assert c == [u64(0x2), 0x4]
}
fn test_multiply_digit_array_01() {
a := [u64(0), 0, 0, 1]
b := [u64(0), 0, 1]
mut c := []u64{len: a.len + b.len}
multiply_digit_array(a, b, mut c)
assert c == [u64(0), 0, 0, 0, 0, 1]
}
fn test_multiply_digit_array_02() {
a := []u64{len: 0}
b := [u64(0), 0, 1]
mut c := []u64{len: a.len + b.len}
multiply_digit_array(a, b, mut c)
assert c == []
c = []u64{len: a.len + b.len}
multiply_digit_array(b, a, mut c)
assert c == []
}
fn test_compare_digit_array_01() {
a := [u64(0), 0, 2]
b := [u64(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 := [u64(0), 0, 2324, 0, 124]
b := [u64(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 := [u64(14)]
b := [u64(2)]
mut q := []u64{len: 1}
mut r := []u64{len: 1}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(7)]
assert r == []u64{len: 0}
}
fn test_divide_digit_array_02() {
a := [u64(14)]
b := [u64(15)]
mut q := []u64{len: 1}
mut r := []u64{len: 1}
divide_digit_array(a, b, mut q, mut r)
assert q == []u64{len: 0}
assert r == a
}
fn test_divide_digit_array_03() {
a := [u64(0), 4]
b := [u64(0), 1]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(4)]
assert r == []u64{len: 0}
}
fn test_divide_digit_array_04() {
a := [u64(2), 4]
b := [u64(0), 1]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(4)]
assert r == [u64(2)]
}
fn test_divide_digit_array_05() {
a := [u64(3)]
b := [u64(2)]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(1)]
assert r == [u64(1)]
}
fn test_left_and_right_shift() {
a := [u64(1), 1, 1]
mut r := [u64(2), 2, 2]
mut b := []u64{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 := [u64(0x0fff_ffff_ffff_ffff)]
shift_digits_left(c, 16, mut c)
assert c == [u64(0x0fff_ffff_ffff_0000), u64(0xffff)]
shift_digits_right(c, 8, mut c)
assert c == [u64(0x0fff_ffff_ffff_ff00), 0xff]
shift_digits_right(c, 16, mut c)
assert c == [u64(0x000f_ffff_ffff_ffff)]
shift_digits_right(c, 16, mut c)
assert c == [u64(0x000f_ffff_ffff)]
shift_digits_right(c, 16, mut c)
assert c == [u64(0x000f_ffff)]
shift_digits_right(c, 40, mut c)
assert c == []u64{len: 0}
}
fn test_or_digit_array() {
a := [u64(10), 10, 10]
b := [u64(5), 5, 5]
mut c := []u64{len: 3, init: 0}
bitwise_or_digit_array(a, b, mut c)
assert c == [u64(15), 15, 15]
bitwise_or_digit_array(a, a, mut c)
assert c == a
x := [u64(10), 10, 10, 42, 42]
y := [u64(2), 2, 5, 2]
mut d := []u64{len: 5, init: 0}
bitwise_or_digit_array(y, x, mut d)
assert d == [u64(10), 10, 15, 42, 42]
}
@@ -0,0 +1,31 @@
module main
import math.big
import benchmark
const n = 2500_000
fn dividing_big_numbers_big_pow() {
d_12 := big.integer_from_int(12)
d_4 := big.integer_from_int(4)
d_10 := big.integer_from_int(10)
mut clock := benchmark.start()
base := d_10.pow(u32(n - 1))
clock.measure('math.big> n: ${n} | base.bit_len: ${base.bit_len()}')
a := d_12 * base
b := d_4 * base
clock.measure('math.big> a.bit_len: ${a.bit_len()} | b.bit_len: ${b.bit_len()}')
c := a / b // c should be 3
clock.measure('math.big> c: ${c} | c.bit_len(): ${c.bit_len()}')
if c.str() != '3' {
println('math.big:error! c.str() == ${c.str()}')
}
if c.bit_len() != 2 {
println('math.big:error! c.bit_len() == ${c.bit_len()}')
}
}
fn main() {
dividing_big_numbers_big_pow()
}
@@ -0,0 +1,85 @@
module main
import benchmark
import math
import math.big
import os
import strconv
// Regression benchmark for issue #21319.
// It mirrors the external edigits workload without printing every line,
// so the timing stays focused on `math.big`.
const default_n = 250_001
const one = big.one_int
const ten = big.c10
fn main() {
mut n := default_n
if os.args.len > 1 {
n = strconv.atoi(os.args[1]) or { default_n }
}
mut clock := benchmark.start()
k := binary_search(n)
clock.measure('k=${k}')
mut p, q := sum_terms(0, k - 1)
clock.measure('sum_terms p.bit_len=${p.bit_len()} q.bit_len=${q.bit_len()}')
p += q
a := ten.pow(u32(n - 1))
clock.measure('pow 10^${n - 1}')
answer := p * a / q
clock.measure('division answer.bit_len=${answer.bit_len()}')
s := answer.str()
clock.measure('str digits=${s.len}')
if s.len != n {
eprintln('unexpected digit count: got ${s.len}, want ${n}')
return
}
println(last_line(s, n))
}
fn sum_terms(a int, b int) (big.Integer, big.Integer) {
if b == a + 1 {
return one, big.integer_from_int(b)
}
mid := (a + b) / 2
p_left, q_left := sum_terms(a, mid)
p_right, q_right := sum_terms(mid, b)
return p_left * q_right + p_right, q_left * q_right
}
fn binary_search(n int) int {
mut a := 0
mut b := 1
for !test_k(n, b) {
a = b
b *= 2
}
for b - a > 1 {
m := (a + b) / 2
if test_k(n, m) {
b = m
} else {
a = m
}
}
return b
}
fn test_k(n int, k int) bool {
if k < 0 {
return false
}
ln_k_factorial := k * (math.log(k) - 1) + 0.5 * math.log(math.tau)
log_10_k_factorial := ln_k_factorial / math.ln10
return log_10_k_factorial >= n + 50
}
fn last_line(s string, n int) string {
chunk_len := if n % 10 == 0 { 10 } else { n % 10 }
start := n - chunk_len
mut line := s[start..n]
for line.len < 10 {
line += ' '
}
return '${line}\t:${n}'
}
+198
View File
@@ -0,0 +1,198 @@
module big
struct JS.BigInt {}
#const jsNumber = Number;
pub struct Number {
}
pub fn new() Number {
return Number{}
}
pub fn from_int(i int) Number {
n := Number{}
#n.value = BigInt(+i)
return n
}
pub fn from_u64(u u64) Number {
n := Number{}
#n.value = BigInt(u.val)
return n
}
pub fn from_hex_string(input string) Number {
n := Number{}
#n.value = BigInt(input.val)
return n
}
pub fn from_string(input string) Number {
n := Number{}
#n.value = BigInt(input.val)
return n
}
pub fn (n &Number) int() int {
r := 0
#r.val = jsNumber(n.val.value)
return r
}
pub fn (n &Number) str() string {
s := ''
#s.str = n.val.value + ""
return s
}
pub fn (a &Number) + (b &Number) Number {
c := Number{}
#c.value = a.val.value + b.val.value
return c
}
pub fn (a &Number) - (b &Number) Number {
c := Number{}
#c.value = a.val.value - b.val.value
return c
}
pub fn (a &Number) / (b &Number) Number {
c := Number{}
#c.value = a.val.value / b.val.value
return c
}
pub fn (a &Number) * (b &Number) Number {
c := Number{}
#c.value = a.val.value * b.val.value
return c
}
/*
pub fn (a &Number) % (b &Number) Number {
c := Number{}
# c.value = a.val.value % b.val.value
return c
}*/
pub fn div_mod(a &Number, b &Number) (Number, Number) {
c := Number{}
d := Number{}
#c.value = a.val.value / b.val.value
#d.value = a.val.value % b.val.value
return c, d
}
pub fn cmp(a &Number, b &Number) int {
res := 0
#if (a.val.value < b.val.value) res.val = -1
#else if (a.val.value > b.val.value) res.val = 1
#else res.val = 0
return res
}
pub fn (a &Number) is_zero() bool {
res := false
#res.val = a.val.value == BigInt(0)
return res
}
pub fn (mut a Number) inc() {
#a.val.value = a.val.value + BigInt(1)
}
pub fn (mut a Number) dec() {
#a.val.value = a.val.value - BigInt(1)
}
pub fn (a &Number) isqrt() Number {
b := Number{}
#let x0 = a.val.value >> 1n
#if (x0) {
#let x1 = (x0 + a.val.value / x0) >> 1n
#while (x1 < x0) {
#x0 = x1
#x1 = (x0 + a.val.value / x0) >> 1n
#}
#b.value = x0
#} else { b.value = a.val.value; }
return b
}
pub fn bitwise_and(a &Number, b &Number) Number {
c := Number{}
#c.value = a.val.value & b.val.value
return c
}
pub fn bitwise_or(a &Number, b &Number) Number {
c := Number{}
#c.value = a.val.value | b.val.value
return c
}
pub fn bitwise_xor(a &Number, b &Number) Number {
c := Number{}
#c.value = a.val.value ^ b.val.value
return c
}
pub fn (a &Number) left_shift(amount int) Number {
c := Number{}
#c.value = a.val.value << BigInt(+amount)
return c
}
pub fn (a &Number) right_shift(amount int) Number {
c := Number{}
#c.value = a.val.value << BigInt(+amount)
return c
}
pub fn (a &Number) clone() Number {
b := Number{}
#b.value = a.val.value
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 factorial_int(n int) Number {
return factorial(from_int(n))
}
+40
View File
@@ -0,0 +1,40 @@
module big
pub const zero_int = Integer{
digits: []u64{len: 0}
signum: 0
is_const: true
}
pub const one_int = positive_integer(1)
pub const two_int = positive_integer(2)
pub const three_int = positive_integer(3)
pub const c0 = zero_int
pub const c1 = positive_integer(1)
pub const c2 = positive_integer(2)
pub const c3 = positive_integer(3)
pub const c4 = positive_integer(4)
pub const c5 = positive_integer(5)
pub const c6 = positive_integer(6)
pub const c7 = positive_integer(7)
pub const c8 = positive_integer(8)
pub const c9 = positive_integer(9)
pub const c10 = positive_integer(10)
pub const c11 = positive_integer(11)
pub const c12 = positive_integer(12)
pub const c13 = positive_integer(13)
pub const c14 = positive_integer(14)
pub const c15 = positive_integer(15)
pub const c16 = positive_integer(16)
pub const c17 = positive_integer(17)
pub const c18 = positive_integer(18)
pub const c19 = positive_integer(19)
pub const c20 = positive_integer(20)
fn positive_integer(x int) Integer {
return Integer{
digits: [u64(x)]
signum: 1
is_const: true
}
}
+20
View File
@@ -0,0 +1,20 @@
import math.big
const d_2 = big.integer_from_int(2)
const d_4 = big.integer_from_int(4)
const d_10 = big.integer_from_int(10)
fn test_dividing_big_numbers() {
mut n := 250_000
base := d_10.pow(u32(n - 1))
eprintln('> n: ${n} | base.bit_len: ${base.bit_len()}')
a := d_4 * base
b := d_2 * base
eprintln('> a.bit_len: ${a.bit_len()} | b.bit_len: ${b.bit_len()}')
assert a.bit_len() == 830481
assert b.bit_len() == 830480
c := a / b // c should be 2
eprintln('> c: ${c} | c.bit_len(): ${c.bit_len()}')
assert c.str() == '2'
assert c.bit_len() == 2
}
File diff suppressed because it is too large. Load diff
+32
View File
@@ -0,0 +1,32 @@
import math.big
fn test_named_consts() {
assert big.zero_int == big.integer_from_int(0)
assert big.one_int == big.integer_from_int(1)
assert big.two_int == big.integer_from_int(2)
assert big.three_int == big.integer_from_int(3)
}
fn test_indexed_consts() {
assert big.c0 == big.integer_from_int(0)
assert big.c1 == big.integer_from_int(1)
assert big.c2 == big.integer_from_int(2)
assert big.c3 == big.integer_from_int(3)
assert big.c4 == big.integer_from_int(4)
assert big.c5 == big.integer_from_int(5)
assert big.c6 == big.integer_from_int(6)
assert big.c7 == big.integer_from_int(7)
assert big.c8 == big.integer_from_int(8)
assert big.c9 == big.integer_from_int(9)
assert big.c10 == big.integer_from_int(10)
assert big.c11 == big.integer_from_int(11)
assert big.c12 == big.integer_from_int(12)
assert big.c13 == big.integer_from_int(13)
assert big.c14 == big.integer_from_int(14)
assert big.c15 == big.integer_from_int(15)
assert big.c16 == big.integer_from_int(16)
assert big.c17 == big.integer_from_int(17)
assert big.c18 == big.integer_from_int(18)
assert big.c19 == big.integer_from_int(19)
assert big.c20 == big.integer_from_int(20)
}
+125
View File
@@ -0,0 +1,125 @@
module big
import math.bits
// help routines for cleaner code but inline for performance
// quicker than BitField.set_bit
@[direct_array_access; inline]
fn bit_set(mut a []u64, n int) {
byte_offset := n / digit_bits
mask := u64(1) << u32(n % digit_bits)
$if debug {
assert a.len >= byte_offset
}
a[byte_offset] |= mask
}
@[direct_array_access]
fn knuth_divide_array_by_array(operand_a []u64, operand_b []u64, mut quotient []u64, mut remainder []u64) {
m := operand_a.len - operand_b.len
n := operand_b.len
mut u := []u64{len: operand_a.len + 1}
mut v := []u64{len: n}
leading_zeros := bits.leading_zeros_64(operand_b.last()) - (64 - digit_bits)
if leading_zeros > 0 {
mut carry := u64(0)
amount := digit_bits - leading_zeros
for i in 0 .. operand_a.len {
temp := (operand_a[i] << leading_zeros) | carry
u[i] = temp & max_digit
carry = operand_a[i] >> amount
}
u[operand_a.len] = carry
carry = 0
for i in 0 .. operand_b.len {
temp := (operand_b[i] << leading_zeros) | carry
v[i] = temp & max_digit
carry = operand_b[i] >> amount
}
} else {
for i in 0 .. operand_a.len {
u[i] = operand_a[i]
}
for i in 0 .. operand_b.len {
v[i] = operand_b[i]
}
}
if remainder.len >= (n + 1) {
remainder.trim(n + 1)
} else {
remainder = []u64{len: n + 1}
}
v_n_1 := v[n - 1]
v_n_2 := v[n - 2]
for j := m; j >= 0; j-- {
u_j_n := u[j + n]
u_j_n_1 := u[j + n - 1]
u_j_n_2 := u[j + n - 2]
mut qhat, mut rhat := bits.div_64(u_j_n >> (64 - digit_bits),
(u_j_n << digit_bits) | u_j_n_1, v_n_1)
mut x1, mut x2 := bits.mul_64(qhat, v_n_2)
x2 = x2 & max_digit
x1 = (x1 << (64 - digit_bits)) | (x2 >> digit_bits)
for greater_than(x1, x2, rhat, u_j_n_2) {
qhat--
prev := rhat
rhat += v_n_1
if rhat < prev {
break
}
x1, x2 = bits.mul_64(qhat, v_n_2)
x2 = x2 & max_digit
x1 = (x1 << (64 - digit_bits)) | (x2 >> digit_bits)
}
mut carry := u64(0)
for i in 0 .. n {
hi, lo := bits.mul_add_64(v[i], qhat, carry)
remainder[i] = lo & max_digit
carry = (hi << (64 - digit_bits)) | (lo >> digit_bits)
}
remainder[n] = carry
mut borrow := u64(0)
for i in 0 .. n + 1 {
result := u[j + i] - remainder[i] - borrow
u[j + i] = result & max_digit
borrow = (result >> digit_bits) & 1
}
if borrow == 1 {
qhat--
carry = u64(0)
for i in 0 .. n {
sum := u[j + i] + v[i] + carry
u[j + i] = sum & max_digit
carry = sum >> digit_bits
}
}
quotient[j] = qhat
}
remainder.delete_last()
if leading_zeros > 0 {
mut carry := u64(0)
max_leading_digit := (u64(1) << leading_zeros) - 1
for i := n - 1; i >= 0; i-- {
current_limb := u[i]
remainder[i] = (current_limb >> leading_zeros) | carry
carry = (current_limb & max_leading_digit) << (digit_bits - leading_zeros)
}
} else {
for i in 0 .. n {
remainder[i] = u[i]
}
}
shrink_tail_zeros(mut quotient)
shrink_tail_zeros(mut remainder)
}
@[inline]
fn greater_than(x1 u64, x2 u64, y1 u64, y2 u64) bool {
return x1 > y1 || (x1 == y1 && x2 > y2)
}
@@ -0,0 +1,71 @@
module big
import rand
fn test_divide_digit_array_03() {
a := [u64(0), 4]
b := [u64(0), 1]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(4)]
assert r == []u64{len: 0}
}
fn test_divide_digit_array_04() {
a := [u64(2), 4]
b := [u64(0), 1]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(4)]
assert r == [u64(2)]
}
fn test_divide_digit_array_05() {
a := [u64(2), 4, 5]
b := [u64(0), 1]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(4), 5]
assert r == [u64(2)]
}
fn test_divide_digit_array_06() {
a := [u64(2), 4, 5, 3]
b := [u64(0), 0x8000]
mut q := []u64{len: a.len - b.len + 1}
mut r := []u64{len: a.len}
divide_digit_array(a, b, mut q, mut r)
assert q == [u64(0xa000_00000000), 0x6000_00000000]
assert r == [u64(2), 4]
}
fn test_many_divisions() {
for _ in 0 .. 100 {
a := random_number(30)
b := random_number(30)
c := a * b
assert c / a == b
assert c / b == a
q, r := a.div_mod(b)
assert (q * b) + r == a
}
}
fn random_number(length int) Integer {
numbers := '0123456789'
mut stri := ''
for _ in 0 .. length {
i := rand.intn(10) or { 0 }
nr := numbers[i]
stri = stri + nr.ascii_str()
}
res := integer_from_string(stri) or { panic(err) }
return res
}
+327
View File
@@ -0,0 +1,327 @@
module big
/*
for a detailed explanation on these internal functions and the algorithms they
are based on refer to https://github.com/vlang/v/pull/18461
*/
// internal struct to make passing montgomery values simpler
struct MontgomeryContext {
n Integer // |modulus|
ni Integer // n^(-1)
rr Integer // for conversions
}
// montgomery calculates a montgomery context for reductions to montgomery space based on
// the modulus provided in the integer `m`; assume m is odd and m != 0
fn (m Integer) montgomery() MontgomeryContext {
$if debug {
assert m != zero_int
assert m.is_odd()
}
n := m.abs()
b := u32(n.bit_len())
return MontgomeryContext{
n: n
// r = 2^(log_2(n))
// ri := multiplicative inverse of r in the ring Z/nZ
// ri * r == 1 (mod n)
// ni = ((ri * 2^(log_2(n))) - 1) / n
ni: (one_int.left_shift(b).mod_inv(n).left_shift(b) - one_int) / n
rr: one_int.left_shift(b * 2) % n
}
}
// mont_odd calculates `a^x (mod m)`, where `m` is odd by reducing `a` to montgomery space
// and then exponentiating the value using the sliding window method and montgomery multiplication
// -----
// assumes a, x > 1 and m is odd
@[direct_array_access]
fn (a Integer) mont_odd(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert m.is_odd()
}
window := get_window_size(u32(x.bit_len()))
mut table := []Integer{len: 1 << window}
ctx := m.montgomery()
aa := if a.signum < 0 || a.abs_cmp(m) >= 0 {
a % m
} else {
a
}
table[0] = aa.to_mont(ctx)
{
d := table[0].mont_mul(table[0], ctx)
for i := 1; i < table.len; i++ {
table[i] = table[i - 1].mont_mul(d, ctx)
}
}
mut r := if m.digits.last() & (u64(1) << (digit_bits - 1)) != 0 {
mut rdigits := []u64{len: m.digits.len}
rdigits[0] = (-m.digits[0]) & max_digit
for i := 1; i < m.digits.len; i++ {
rdigits[i] = (~m.digits[i]) & max_digit
}
Integer{
digits: rdigits
signum: 1
}
} else {
one_int.to_mont(ctx)
}
mut start := true
mut wstart := x.bit_len() - 1
mut wvalue := 0
mut wend := 0
for {
if !x.get_bit(u32(wstart)) {
if !start {
r = r.mont_mul(r, ctx)
}
if wstart == 0 {
break
}
wstart--
continue
}
wvalue = 1
wend = 0
for i := 1; i < window; i++ {
if wstart - i < 0 {
break
}
if x.get_bit(u32(wstart - i)) {
wvalue <<= (i - wend)
wvalue |= 1
wend = i
}
}
j := wend + 1
if !start {
for i := 0; i < j; i++ {
r = r.mont_mul(r, ctx)
}
}
r = r.mont_mul(table[wvalue >> 1], ctx)
wstart -= j
wvalue = 0
start = false
if wstart < 0 {
break
}
}
return r.from_mont(ctx)
}
// mont_even calculates `a^x (mod m)` where `m` is even. This is done by factoring the modulus
// `m` into an odd integer `m1` and an even multiple of 2, which we'll call m2.
// We then calculate:
// x1 = a^x (mod m1)
// x2 = a^x (mod m2)
//
// Exponentiation with the modulus `m1` can be done using the traditional montgomery method,
// whereas `m2` is done using binary exponentiation modulo `m2`, which is fast seeing as we
// simply mask the low bits.
//
// The result `y` then satisfies (where `==` denotes congruence):
// y == x1 (mod m1)
// y == x2 (mod m2)
//
// We then use the Chinese Remainder Theorem (mixed-radix conversion algorithm) to calculate `y`.
// y = x1 + m1 * t
// where
// t = (x2 - x1) * m1^(-1) (mod m2)
//
// The multiplicative inverse of m1 in Z/m2Z exists since it is odd, therefore we can safely
// use the unchecked internal function.
//
// See Montgomery Reduction with Even Modulus by Çetin Kaya Koç
// (https://cetinkayakoc.net/docs/j34.pdf)
// -----
// assumes a, x > 1 and m is even
@[direct_array_access]
fn (a Integer) mont_even(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert !m.is_odd()
}
m1, j := m.rsh_to_set_bit()
m2 := one_int.left_shift(j)
$if debug {
assert m1 * m2 == m
assert m1.is_odd() && !m2.is_odd()
}
mut x1 := a.mont_odd(x, m1)
mut x2 := a.exp_binary(x, m2)
m2n := u32(m2.bit_len()) - 1
m1i := m1.mod_inv(m2)
$if debug {
assert (m1i * m1).mask_bits(m2n) == one_int
}
t1 := x1.mask_bits(m2n)
t2 := x2.mask_bits(m2n)
t := (if t2.abs_cmp(t1) >= 0 {
(t2 - t1).mask_bits(m2n)
} else {
// (x2 - x1) % m2 = 1 + ((~((x2 % m2) - (x1 % m2))) % m2)
(t1 - t2).abs().bitwise_not().mask_bits(m2n) + one_int
} * m1i).mask_bits(m2n)
return x1 + m1 * t
}
// exp_binary calculates `a^x (mod m)`, where m is a power of 2
// -----
// assumes a, x > 1 and m = 2^n
@[direct_array_access]
fn (a Integer) exp_binary(x Integer, m Integer) Integer {
$if debug {
assert a > one_int && x > one_int
assert m.is_power_of_2()
}
n := u32(m.bit_len()) - 1
window := get_window_size(u32(x.bit_len()))
mut table := []Integer{len: 1 << window}
// table[i] = a^i + 1, since a^0 is known to be 1, there is no point
// in eventually multiplying by one, so the for loop part continues until it
// meets a block starting with a set bit
table[0] = a.mask_bits(n)
d := (table[0] * table[0]).mask_bits(n)
for i := 1; i < table.len; i++ {
table[i] = (table[i - 1] * d).mask_bits(n)
}
mut r := one_int
mut start := true
mut wstart := x.bit_len() - 1
mut wend := 0
mut wvalue := 1
for wstart >= 0 {
if !x.get_bit(u32(wstart)) {
// no point squaring while r = 1
if !start {
r = (r * r).mask_bits(n)
}
if wstart == 0 {
break
}
wstart--
continue
}
// the bit x[wstart] is now known to be 1, so no reason to check it again
for i := 1; i < window; i++ {
if wstart - i < 0 {
break
}
if x.get_bit(u32(wstart - i)) {
wvalue <<= (i - wend) // i - wend is the amount of 0 bits that have been read
wvalue |= 1
wend = i
}
}
j := wend + 1
// same as before; r has not been populated yet, so squaring wouldn't do anything
if !start {
for i := 0; i < j; i++ {
r = (r * r).mask_bits(n)
}
}
r = (r * table[wvalue >> 1]).mask_bits(n)
wstart -= j
wvalue = 1
wend = 0
start = false
}
return r.mask_bits(n)
}
// generally sticking to a window size of 4 for sliding window exponentiation
// works well as the table stays relatively small and the blocks aren't too large.
// though in terms of larger exponents it's faster to use larger windows (going over
// a window size of 6, would cause extremely large table sizes, hindering performance)
//
// 6 is already a large window to use, requiring 64 elements in the table, so we'll
// limit it to only the largest of exponents
//
// according to the paper on montgomery multiplication by Shay Gueron, for the
// case of the exponent being 512 bits a window size of 5 is considered optimal
@[inline]
fn get_window_size(n u32) int {
return if n > 768 {
6
} else if n > 256 {
5
} else if n > 32 {
4
} else {
3
}
}
// mont_mul performs multiplication of two variables in montgomery
// space and reduces the result to montgomery space
fn (a Integer) mont_mul(b Integer, ctx MontgomeryContext) Integer {
if (a.digits.len + b.digits.len) > 2 * ctx.n.digits.len {
return zero_int
}
t := a * b
return t.from_mont(ctx)
}
fn (a Integer) to_mont(ctx MontgomeryContext) Integer {
return a.mont_mul(ctx.rr, ctx)
}
// See Fig. 1. "A Montgomery Reduction lemma" in
// Efficient Software Implementations of Modular Exponentiation by Shay Gueron
// (https://eprint.iacr.org/2011/239.pdf)
fn (a Integer) from_mont(ctx MontgomeryContext) Integer {
log2n := u32(ctx.n.bit_len())
r := (a + ((a.mask_bits(log2n) * ctx.ni).mask_bits(log2n) * ctx.n)).right_shift(log2n)
return if r.abs_cmp(ctx.n) >= 0 {
r - ctx.n
} else {
r
}
}
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
module big
// from_json_number implements a custom decoder for json2
pub fn (mut result Integer) from_json_number(raw_number string) ! {
mut index := 0
mut is_negative := false
if raw_number[0] == `-` {
is_negative = true
index++
}
ten := integer_from_int(10)
for index < raw_number.len {
digit := raw_number[index] - `0`
if digit > 9 { // comma, e and E are all smaller 0 in ASCII so they underflow
return error('expected integer but got real number')
}
result = (result * ten) + integer_from_int(int(digit))
index++
}
if is_negative {
result = result * integer_from_int(-1)
}
}
// to_json implements a custom encoder for json2
pub fn (result Integer) to_json() string {
return result.str()
}
@@ -0,0 +1,65 @@
import time
import math.big
const t = time.new_stopwatch()
// a := big.integer_from_i64(2).pow(123123123)
// println(a)
fn timed_println(msg string) {
timed_println_extended(t, msg)
}
fn timed_println_extended(t time.StopWatch, msg string) {
println('${t.elapsed().microseconds():12} µs | ${msg}')
}
fn f(x big.Integer, y int) big.Integer {
timed_println('f x y, y=${y:12}')
if y & 1 == 0 {
return f(x * x, y / 2)
}
if y == 1 {
return x
}
return g(x * x, y / 2, x)
}
fn g(x big.Integer, y int, z big.Integer) big.Integer {
timed_println('g x y z, y=${y:12}')
if y & 1 == 0 {
return g(x * x, y / 2, z)
}
if y == 1 {
return x * z
}
return g(x * x, y / 2, x * z)
}
fn calculate_and_measure(calc_label string, cb fn () big.Integer) string {
sw := time.new_stopwatch()
timed_println_extended(sw, 'start')
a := cb()
timed_println_extended(sw, 'done ${calc_label}')
timed_println_extended(sw, 'a.bit_len(): ${a.bit_len():12}')
timed_println_extended(sw, 'before a.str()')
// s := a.hex() // hex is very fast since it does not need to do divisions at all
s := a.str()
timed_println_extended(sw, 'after a.str()')
dump(s.len)
dump(s#[0..10])
dump(s#[-10..])
timed_println_extended(sw, 'finish')
return s
}
fn test_exponentiation() {
res1 := calculate_and_measure('f(x, y)', fn () big.Integer {
return f(big.integer_from_int(2), 66777)
})
res2 := calculate_and_measure('big.int(x).pow(y)', fn () big.Integer {
return big.integer_from_i64(2).pow(66777)
})
assert res1 == res2
}
+26
View File
@@ -0,0 +1,26 @@
module big
@[inline]
fn imax(a int, b int) int {
return if a > b { a } else { b }
}
@[inline]
fn imin(a int, b int) int {
return if a < b { a } else { b }
}
@[inline]
fn umax(a u32, b u32) u32 {
return if a > b { a } else { b }
}
@[inline]
fn umin(a u32, b u32) u32 {
return if a < b { a } else { b }
}
@[inline]
fn iabs(v int) int {
return if v > 0 { v } else { -v }
}
+368
View File
@@ -0,0 +1,368 @@
module big
import strings
@[direct_array_access; inline]
fn shrink_tail_zeros(mut a []u64) {
mut alen := a.len
for alen > 0 && a[alen - 1] == 0 {
alen--
}
unsafe {
a.len = alen
}
}
@[direct_array_access; inline]
fn (i &Integer) shrink_tail_zeros() {
mut alen := i.digits.len
for alen > 0 && i.digits[alen - 1] == 0 {
alen--
}
unsafe {
i.digits.len = alen
}
}
// debug_u64_str output a `[]u64`
@[direct_array_access]
fn debug_u64_str(a []u64) string {
mut sb := strings.new_builder(30)
sb.write_string('[')
mut first := true
for i in 0 .. a.len {
if !first {
sb.write_string(', ')
}
sb.write_string('0x${a[i].hex():016}')
first = false
}
sb.write_string(']')
return sb.str()
}
// debug_u32_str for 32bit bignum test only, convert a `[]u64` to `[]u32`.
@[direct_array_access]
fn debug_u32_str(a []u64) string {
mut b := []u32{cap: a.len * 2}
mut curr_u32 := u32(0)
mut bits_collected := 0
for w in a {
for i in 0 .. digit_bits {
bit := (w >> i) & 1
curr_u32 |= u32(bit) << bits_collected
bits_collected++
if bits_collected == 32 {
b << curr_u32
curr_u32 = 0
bits_collected = 0
}
}
}
if bits_collected > 0 {
b << curr_u32
}
mut blen := b.len
for blen > 0 && b[blen - 1] == 0 {
blen--
}
unsafe {
b.len = blen
}
mut sb := strings.new_builder(30)
sb.write_string('[')
mut first := true
for i in 0 .. b.len {
if !first {
sb.write_string(', ')
}
sb.write_string('0x${b[i].hex():08}')
first = false
}
sb.write_string(']')
return sb.str()
}
@[direct_array_access; inline]
fn found_multiplication_base_case(operand_a []u64, operand_b []u64, mut storage []u64) bool {
// base case necessary to end recursion
if operand_a.len == 0 || operand_b.len == 0 {
storage.clear()
return true
}
if operand_a.len < operand_b.len {
multiply_digit_array(operand_b, operand_a, mut storage)
return true
}
if operand_b.len == 1 {
multiply_array_by_digit(operand_a, operand_b[0], mut storage)
return true
}
return false
}
// karatsuba algorithm for multiplication
// possible optimisations:
// - transform one or all the recurrences in loops
@[direct_array_access]
fn karatsuba_multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
if found_multiplication_base_case(operand_a, operand_b, mut storage) {
return
}
// thanks to the base cases we can pass zero-length arrays to the mult func
half := imax(operand_a.len, operand_b.len) / 2
mut a_l := unsafe { operand_a[0..half] }
mut a_h := unsafe { operand_a[half..] }
mut b_l := []u64{}
mut b_h := []u64{}
if half <= operand_b.len {
b_l = unsafe { operand_b[0..half] }
b_h = unsafe { operand_b[half..] }
} else {
b_l = unsafe { operand_b }
// b_h = []u64{}
}
shrink_tail_zeros(mut a_l)
shrink_tail_zeros(mut a_h)
shrink_tail_zeros(mut b_l)
shrink_tail_zeros(mut b_h)
// use storage for p_1 to avoid allocation and copy later
multiply_digit_array(a_h, b_h, mut storage)
mut p_3 := []u64{len: a_l.len + b_l.len + 1}
multiply_digit_array(a_l, b_l, mut p_3)
mut tmp_1 := []u64{len: imax(a_h.len, a_l.len) + 1}
mut tmp_2 := []u64{len: imax(b_h.len, b_l.len) + 1}
add_digit_array(a_h, a_l, mut tmp_1)
add_digit_array(b_h, b_l, mut tmp_2)
mut p_2 := []u64{len: operand_a.len + operand_b.len + 1}
multiply_digit_array(tmp_1, tmp_2, mut p_2)
subtract_in_place(mut p_2, storage) // p_1
subtract_in_place(mut p_2, p_3)
// return p_1.left_shift(2 * u32(half * 32)) + p_2.left_shift(u32(half * 32)) + p_3
left_shift_digits_in_place(mut storage, 2 * half)
left_shift_digits_in_place(mut p_2, half)
add_in_place(mut storage, p_2)
add_in_place(mut storage, p_3)
shrink_tail_zeros(mut storage)
}
// TODO: the manualfree tag here is a workaround for compilation with -autofree. Remove it, when the -autofree bug is fixed.
@[direct_array_access; manualfree]
fn toom3_multiply_digit_array(operand_a []u64, operand_b []u64, mut storage []u64) {
if found_multiplication_base_case(operand_a, operand_b, mut storage) {
return
}
// After the base case, we have operand_a as the larger integer in terms of digit length
// k is the length (in u64 digits) of the lower order slices
k := (operand_a.len + 2) / 3
k2 := 2 * k
// The pieces of the calculation need to be worked on as proper big.Integers
// because the intermediate results can be negative. After recombination, the
// final result will be positive.
// Slices of a and b
a0 := Integer{
digits: unsafe { operand_a[..k] }
signum: if operand_a[..k].all(it == 0) {
0
} else {
1
}
}
a0.shrink_tail_zeros()
a1 := Integer{
digits: unsafe { operand_a[k..k2] }
signum: if operand_a[k..k2].all(it == 0) {
0
} else {
1
}
}
a1.shrink_tail_zeros()
a2 := Integer{
digits: unsafe { operand_a[k2..] }
signum: 1
}
// Zero arrays by default
mut b0 := zero_int.clone()
mut b1 := zero_int.clone()
mut b2 := zero_int.clone()
if operand_b.len < k {
b0 = Integer{
digits: operand_b
signum: 1
}
} else if operand_b.len < k2 {
if !operand_b[..k].all(it == 0) {
b0 = Integer{
digits: operand_b[..k].clone()
signum: 1
}
}
b0.shrink_tail_zeros()
b1 = Integer{
digits: operand_b[k..].clone()
signum: 1
}
} else {
if !operand_b[..k].all(it == 0) {
b0 = Integer{
digits: operand_b[..k].clone()
signum: 1
}
}
b0.shrink_tail_zeros()
if !operand_b[k..k2].all(it == 0) {
b1 = Integer{
digits: operand_b[k..k2].clone()
signum: 1
}
}
b1.shrink_tail_zeros()
b2 = Integer{
digits: operand_b[k2..].clone()
signum: 1
}
}
// https://en.wikipedia.org/wiki/Toom%E2%80%93Cook_multiplication#Details
// DOI: 10.1007/978-3-540-73074-3_10
p0 := a0 * b0
mut ptemp := a2 + a0
mut qtemp := b2 + b0
vm1 := (ptemp - a1) * (qtemp - b1)
ptemp += a1
qtemp += b1
p1 := ptemp * qtemp
p2 := ((ptemp + a2).left_shift(1) - a0) * ((qtemp + b2).left_shift(1) - b0)
pinf := a2 * b2
mut t2, _ := (p2 - vm1).div_mod_internal(three_int)
mut tm1 := (p1 - vm1).right_shift(1)
mut t1 := p1 - p0
t2 = (t2 - t1).right_shift(1)
t1 = (t1 - tm1 - pinf)
t2 = t2 - pinf.left_shift(1)
tm1 = tm1 - t2
// shift amount
s := u32(k) * digit_bits
result := (((pinf.left_shift(s) + t2).left_shift(s) + t1).left_shift(s) + tm1).left_shift(s) +
p0
storage = result.digits.clone()
}
@[inline]
fn pow2(k int) Integer {
mut ret := []u64{len: (k / digit_bits) + 1}
bit_set(mut ret, k)
return Integer{
signum: 1
digits: ret
}
}
// optimized left shift in place. amount must be positive
fn left_shift_digits_in_place(mut a []u64, amount int) {
// this is actual in builtin/array.v, prepend_many (private fn)
// x := []u64{ len : amount }
// a.prepend_many(&x[0], amount)
old_len := a.len
elem_size := a.element_size
unsafe {
a.grow_len(amount)
sptr := &u8(a.data)
dptr := &u8(a.data) + u64(amount) * u64(elem_size)
vmemmove(dptr, sptr, u64(old_len) * u64(elem_size))
vmemset(sptr, 0, u64(amount) * u64(elem_size))
}
}
// optimized right shift in place. amount must be positive
fn right_shift_digits_in_place(mut a []u64, amount int) {
a.drop(amount)
}
// operand b can be greater than operand a
// the capacity of both array is supposed to be sufficient
@[direct_array_access; inline]
fn add_in_place(mut a []u64, b []u64) {
len_a := a.len
len_b := b.len
max := imax(len_a, len_b)
min := imin(len_a, len_b)
mut carry := u64(0)
for index in 0 .. min {
partial := carry + a[index] + b[index]
a[index] = u64(partial) & max_digit
carry = u64(partial >> digit_bits)
}
if len_a >= len_b {
for index in min .. max {
partial := carry + a[index]
a[index] = u64(partial) & max_digit
carry = u64(partial >> digit_bits)
}
} else {
for index in min .. max {
partial := carry + b[index]
a << u64(partial) & max_digit
carry = u64(partial >> digit_bits)
}
}
if carry > 0 {
a << carry
}
}
// a := a - b supposed a >= b
@[direct_array_access; inline]
fn subtract_in_place(mut a []u64, b []u64) {
len_a := a.len
len_b := b.len
max := imax(len_a, len_b)
min := imin(len_a, len_b)
mut borrow := false
for index in 0 .. min {
mut a_digit := a[index]
b_digit := b[index] + if borrow { u64(1) } else { u64(0) }
borrow = a_digit < b_digit
if borrow {
a_digit = a_digit | (u64(1) << digit_bits)
}
a[index] = a_digit - b_digit
}
if len_a >= len_b {
for index in min .. max {
mut a_digit := a[index]
b_digit := if borrow { u64(1) } else { u64(0) }
borrow = a_digit < b_digit
if borrow {
a_digit = a_digit | (u64(1) << digit_bits)
}
a[index] = a_digit - b_digit
}
} else { // if len.b > len.a return zero
a.clear()
}
}
@@ -0,0 +1,130 @@
module big
fn test_add_in_place() {
mut a := [u64(1), 2, 3]
mut b := [u64(5), 6, 7]
add_in_place(mut a, b)
assert a == [u64(6), 8, 10]
a = [u64(11), 10, 11, 12]
b = [u64(1), 2]
add_in_place(mut a, b)
assert a == [u64(12), 12, 11, 12]
a = []u64{cap: 4}
a << u64(1)
a << u64(2)
b = [u64(3), 4, 5, 6]
add_in_place(mut a, b)
assert a == [u64(4), 6, 5, 6]
a = [u64(0x0423efab_3ce9124b), 0x1438]
b = [u64(0x0d1dd122_db166062)]
add_in_place(mut a, b)
assert a == [u64(0x0141c0ce_17ff72ad), 0x1439]
}
fn test_left_shift_digits_in_place() {
mut a := [u64(5), 6, 7, 8]
left_shift_digits_in_place(mut a, 2)
assert a == [u64(0), 0, 5, 6, 7, 8]
}
fn test_multiply_karatsuba_01() {
mut a := [u64(3)]
mut b := []u64{}
mut c := []u64{len: a.len + b.len, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == []u64{}
a = []u64{}
b = [u64(4)]
c = []u64{len: a.len + b.len, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == []u64{}
a = [u64(3)]
b = [u64(1)]
c = []u64{len: a.len + b.len, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == a
a = [u64(1)]
b = [u64(5)]
c = []u64{len: a.len + b.len, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == b
a = [u64(1234)]
b = [u64(567)]
c = []u64{len: a.len + b.len + 1, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == [u64(699_678)]
a = [u64(0x17ff72ad), 0x1439]
b = [u64(0x30df2ea6)]
c = []u64{len: a.len + b.len + 1, init: 0}
karatsuba_multiply_digit_array(a, b, mut c)
assert c == [u64(0x0494d164_caf2722e), 0x3dc_51565af6]
a_operand := integer_from_string('95484736384949495947362') or { panic(err) }
b_operand := integer_from_string('39474638493') or { panic(err) }
c = []u64{len: a_operand.digits.len + b_operand.digits.len, init: 0}
karatsuba_multiply_digit_array(a_operand.digits, b_operand.digits, mut c)
expected := integer_from_string('3769225450395285038584683507005466') or { panic(err) }
assert c == expected.digits
}
fn test_multiply_karatsuba_02() {
a := integer_from_string('53575430359313366047421252453000090528070240585276680372187519418517552556246806124659918940784792906379733645877657341259357264284615702179922887873492874019672838874121154927105373025311855709389770910765') or {
panic(err)
}
b := integer_from_string('977091076523237491790970633699383779582771973038531457285598238843271083830214915826312193418602834034688531898668229388286706296786321423078510899614439367') or {
panic(err)
}
mut c := []u64{len: a.digits.len + b.digits.len + 1, init: 0}
karatsuba_multiply_digit_array(a.digits, b.digits, mut c)
expected := integer_from_string('52348074924977237255285644820010078601114587486470740900886892189662650320988400136613780986308710610258879824881256666730655821800564143426560480113864123642197317383052431412305975584645367703594190956925565749714310612399025459615546540332117815550470167143256687163102859337019449165214274088466835988832405507818643018779158891710706073875995722420460085755') or {
panic(err)
}
assert c == expected.digits
}
fn test_multiply_karatsuba_03() {
a := integer_from_string('9729117383001812976929423642') or { panic(err) }
b := integer_from_string('36889625830') or { panic(err) }
mut c := []u64{len: a.digits.len + b.digits.len + 1, init: 0}
karatsuba_multiply_digit_array(a.digits, b.digits, mut c)
expected := integer_from_string('358903499915085682930564860470935872860') or { panic(err) }
assert c == expected.digits
}
fn test_multiply_karatsuba_04() {
a := integer_from_string('3497162698306482686971441543687784015323935188659503993757455872811087386614092419985044037321104919528005068133951787970585537874489904111916938512842847091721349488467692801057152512166916236213184367524288990504452781825929907470995493661309646347066613682493568745346493010003413738989626609201116716247487999505270467120147815127162127731356094308578608824651183210782207714100237729572853345375454949172401042315228315798079225822021787648873812084227136884600729940854667658626208586874696517348634844052703490897572232568447636899591259434294094321317182661767424480393673432463592896336498353071042650799050700710267095231586270043139333453041015532516541075995479058358831063322267227185753872164375721426686162668623592972867871620133325684441794121727984491920980314378165848724981409299885843916328147796348091243626516406976056911085263146147809470413030865257211209404793514075883680777679138493578810794788543952808891095680872267690') or {
panic(err)
}
b := integer_from_string('3731153765349978524337790303019073866169615820236360525860598113101007652419849831445556596548560058884406106275477847069475858381339095110646794630677741924575724730195310383260858937531720778415641064228137265209604913544897683432011584846544175241128160109960448428720014016539849270207788214347700420341097980912654975389446512856552635037966995033809488867690903720129762695314322725472787603000346202896778207987391285985804181406019619338215824347026372158857600803429407141531830203430317068399662548922504444591385274908074684241297752512843236588392255573848392016559311506271535791162151101220135017417159573887941542933118000377620518732836102365066672711767692414034390790360321914677167248083633551615232080788875425342060374021891940380358579307475843181010943250359217102987258298') or {
panic(err)
}
mut c := []u64{len: a.digits.len + b.digits.len + 1, init: 0}
karatsuba_multiply_digit_array(a.digits, b.digits, mut c)
expected := integer_from_string('13048451769827723841923278321193855241872058428961713256963598223823113544308869393875481721028040256602323122921447247203223525228006623227671899134332670311746731440890333942554337434694808695934023689467815943095478675997839202402226439648752044627367822829114336020280929447282163468585404769209994615771773294733509244673189891278506538595789870783779458539371487749876399583947052094519945323844069814095194450349814584625148870057340788686115533159501329566111170880650412359779760456808393370185410432176572682144365401835368082749637208673417028234063907368810782078088911618126690572051133815667647041419960704854062060909165346545952623192359395985743203202132668410599975580175587551065836786982237372286798893118604373993845408861570111075107858370728022568891638898121296878893306306949816814132427209493260832613019444633237775219695833279678133602467177003429529917049633056431504426776487440348449903443579642102845765312131382153105184606682393976592634403346380092701679847372217955349096619505179079762928343558899980175648735397570586605980720828687524561573123038494159647318551197545496201465276098212580839445369200418315000310508759594006187422953054821725336960756926970677282806506256927313164107160898391061464246294174106905930356469329214907846583235734490370187185094462047618230289621171427228984027756484384136106088551265698775255811805670865291484911854071447316265726194982034568878612017100992037975737759552371045887134952857158066446970434610533685859910727214440334704089405629838823453640146362193811088002789803040768301613468217974726406918247619138081429486763003592049227953605769429261539079312619553867710373453222399692311140251766121447367352413232353894344679702619305784387721023140535029791620') or {
panic(err)
}
assert c == expected.digits
}
fn test_multiply_karatsuba_05() {
a := integer_from_string('82493285896514075384534758557935745817962515879835743030783040173330112080804455282128666887768950832142482683217121022767045108431288465029812097859309605797374125923106819516889369175652710257114598577149674647352808070074171293463437071337278575658048692496764590565606837743827030666885471141044114152998041176796810186287791052484762784126725875326862901808213516742983471605885175506715101338028877662099324668508172829243608350258614718310497987744299914749640568556948763145778198753554058467050519667096099833770026489285130153597761026274548126098456173815617842498193772432207501694106867673557416973930670286653441130602377920992435485420446072373786632480794952955873161165115041514702778052793282025846106368965034233866947381721682937351649336413571927812528541159171383204511499552013936155419845055011752388749268195206809573519780613814964112063870748954135343076802252512193521886335164017829447109689695709486039190070000245645414910990278895308232897116499341219946699993851317981803815406516602176881967155129969593527319125237096519803243326797168917141748725279791872386421043580031403145024863609187112385918738114802920061988765220468749078618853299694217869902560103452546750214562467076096135222593114183955469963751326883227094769527730223248003306708953970243886519739552586227940684171242302412915186263300531140588498540475339456080545078964144209118163323545928290833439765099112126702760509258061959449977429070215529070401124287712461846696193134436630934717425952944747339686188011926730221707166586372593503352250914537732533953216003449759271968770421909127444731638825893567138749890195444') or {
panic(err)
}
b := integer_from_string('6131999155203247409089965800322203420453654507953806420664043731807402839483789086591425043878906721774222779997525063107602234437085033473124680861190605857734959468536446941493399655926830326691521621629120060373092027010394244758024141037091879171132413714138502869706470511932123207420626930454253770927552857807363136786489394763374159969607962219873240941060072539904794844154488056908195189396404340107989455229902431972663610868653304103396580746811591826044603465964167164178855966898012392223090630560777990379102734550082243603230894035356131452642667384300201186297016843973905130369865474318465241408259975202340234896078010895740058413587215886548145454236789540259643610072467034822757986309311709163062352204171299868075798237348977707372770035406598475786685283610490871427030552271811065910679040103566128693521437169494686602257958511710409941630744336034132463653071078769355257935175422990452306401119325390221264671263162134241884024846471010012913485967133615252263790910226344828197924602249009133593805769333128797013042594573917849267639752846975907650362497446525930636106580780824323557414269051915905993675310076325449434427323319596509995607027978958874919018609350403661403557093530969901119390174552941500745876099234877620450622478016638926607899983456508753736077292767888656321808232398065656946197839116825276017609730557227380499217716159012979059487418587202959339426112335872029689748557894665457579061382636201338034208646424996597993168272103220242687875466825791773419606359011555661467526139097341579632208557586297052223542776250948355945042246570') or {
panic(err)
}
mut c := []u64{len: a.digits.len + b.digits.len + 1, init: 0}
karatsuba_multiply_digit_array(a.digits, b.digits, mut c)
expected := integer_from_string('505848759427364274329357741986216605130929977294192546489509210457601900426556024040073016771820686868026437733614267409521396918447284490340389690485942051363279925801363126432544321078568099151287021886296438619123380168827268412907813594659842321798217885085110398790053409701983461801115224781834023082890662873169191504305955687046526953897067545715710660155497646914961948331236724535698679813769093322003853124540927645162647300288136882363116067195184081346020194278820548735254637692857032965408070350907222436479366121383668103515786877197427062836511944846826932480466793561731962606417667287322005882211404162719492993874592857953397512491054676297738305916085478022723318784939770402209256271554551983534921497675890891312043569145634049147693960076337369503134427352787659326205647773748112716745925158178083868574895622495928425018774779251441610879114247950357970220146481766134464929967308718872255190412874659776500033163244838173195170196127430202488333101394598915495516818921703991533768617658933173526938837897969225258938562812209445135532692302337200334632389376610492768735714190299971580399753641472989662439382540912225551340987306457743400281084947902809687085442657520101417063633057957437817329020615384515166388289331369947059960847133614170679450523810659652782987668106695354035493369448442611758156006527485718905514811065321814359706644699194418190701868505707278984229585722369789551619919906205950348606361748281997782424695650973254173837814677612994239768420808870410390373336826091130971864943060313050478750611821098669520946650257575417245766405176878592155758047549228495747853203792369590850631203019173404179987735732830481798878566582556613534822512685665712663431843718669560669865410543096239869112140888737377028624106518359554511507606387843187232302200517475850782456324239188729330760193745759978024087469060136973622979394674161020956014241092961397194927506142983436789500109128138664821498501821236619524363279857097783139006599000739982697284955344277927297022159974340926721938079595242213432080401390674728369851144911551677647524015332696130827540662024113950127956097630202663581097770816523549988139863573933413116244923387554856120868464947660075936449421302491693593834507504433415086543597651267221343834170846329492147815735045024399026251779389321698355035556629087431166188787768730306310422839817575075342877250911353135209339455830445625001426381558448651172971413260611230589795224559058399088555025826331277804189489960583576819035715077379287444129934501443336913174870788226087158999934636025721931831136227889916792188808832812760406918544186979726578808350730384441425398168139422687286960377555987296985431654502712799904224867124393655074866476410224402965420326358438396015233973741214619430521493940712748773125913358615541385902712067643691280755344861590017706417595031324052737978011814936301852189889555514450129648152568220313555245236446470869647730471752637583335395835914360683070164833354933631599763359799906362664251738450678551934386687346359703853569505426433767046696609137654729946153837937103113817350588833581432259043880508333957686597572923322695933631607569689529867145971190208528802200404369790036623426263214138627080') or {
panic(err)
}
assert c == expected.digits
}