mirror of
https://github.com/vlang/v.git
synced 2025-09-13 22:42:26 +03:00
125 lines
3 KiB
V
125 lines
3 KiB
V
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)
|
|
}
|