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

math.big: reduce memory usage of Integer.str() (free intermediary Integers), optimise some operations using [direct_array_access] (#14353)

This commit is contained in:
Delyan Angelov
2022-05-13 08:21:34 +03:00
committed by GitHub
parent 3c95504a35
commit ed12a5c84c
6 changed files with 186 additions and 98 deletions

View File

@ -4,6 +4,17 @@ import math
import math.bits
import strings
[direct_array_access; inline]
fn shrink_tail_zeros(mut a []u32) {
mut alen := a.len
for alen > 0 && a[alen - 1] == 0 {
alen--
}
unsafe {
a.len = alen
}
}
// suppose operand_a bigger than operand_b and both not null.
// Both quotient and remaider are already allocated but of length 0
fn newton_divide_array_by_array(operand_a []u32, operand_b []u32, mut quotient []u32, mut remainder []u32) {
@ -47,9 +58,7 @@ fn newton_divide_array_by_array(operand_a []u32, operand_b []u32, mut quotient [
quotient = q.digits
remainder = r.digits
for remainder.len > 0 && remainder.last() == 0 {
remainder.delete_last()
}
shrink_tail_zeros(mut remainder)
}
[inline]
@ -57,7 +66,7 @@ fn bit_length(a Integer) int {
return a.digits.len * 32 - bits.leading_zeros_32(a.digits.last())
}
[inline]
[direct_array_access; inline]
fn debug_u32_str(a []u32) string {
mut sb := strings.new_builder(30)
sb.write_string('[')
@ -76,12 +85,11 @@ fn debug_u32_str(a []u32) string {
// karatsuba algorithm for multiplication
// possible optimisations:
// - transform one or all the recurrences in loops
[direct_array_access]
fn karatsuba_multiply_digit_array(operand_a []u32, operand_b []u32, mut storage []u32) {
// base case necessary to end recursion
if operand_a.len == 0 || operand_b.len == 0 {
for storage.len > 0 {
storage.delete_last()
}
storage.clear()
return
}
@ -115,15 +123,15 @@ fn karatsuba_multiply_digit_array(operand_a []u32, operand_b []u32, mut storage
// use storage for p_1 to avoid allocation and copy later
multiply_digit_array(a_h, b_h, mut storage)
mut p_3 := []u32{len: a_l.len + b_l.len + 1, init: 0}
mut p_3 := []u32{len: a_l.len + b_l.len + 1}
multiply_digit_array(a_l, b_l, mut p_3)
mut tmp_1 := []u32{len: math.max(a_h.len, a_l.len) + 1, init: 0}
mut tmp_2 := []u32{len: math.max(b_h.len, b_l.len) + 1, init: 0}
mut tmp_1 := []u32{len: math.max(a_h.len, a_l.len) + 1}
mut tmp_2 := []u32{len: math.max(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 := []u32{len: operand_a.len + operand_b.len + 1, init: 0}
mut p_2 := []u32{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)
@ -134,14 +142,12 @@ fn karatsuba_multiply_digit_array(operand_a []u32, operand_b []u32, mut storage
add_in_place(mut storage, p_2)
add_in_place(mut storage, p_3)
for storage.len > 0 && storage.last() == 0 {
storage.delete_last()
}
shrink_tail_zeros(mut storage)
}
[inline]
fn pow2(k int) Integer {
mut ret := []u32{len: (k >> 5) + 1, init: 0}
mut ret := []u32{len: (k >> 5) + 1}
bit_set(mut ret, k)
return Integer{
signum: 1
@ -150,6 +156,7 @@ fn pow2(k int) Integer {
}
// optimized left shift of full u8(s) in place. byte_nb must be positive
[direct_array_access]
fn lshift_byte_in_place(mut a []u32, byte_nb int) {
a_len := a.len
// control or allocate capacity
@ -166,7 +173,7 @@ fn lshift_byte_in_place(mut a []u32, byte_nb int) {
// operand b can be greater than operand a
// the capacity of both array is supposed to be sufficient
[inline]
[direct_array_access; inline]
fn add_in_place(mut a []u32, b []u32) {
len_a := a.len
len_b := b.len
@ -194,6 +201,7 @@ fn add_in_place(mut a []u32, b []u32) {
}
// a := a - b supposed a >= b
[direct_array_access]
fn subtract_in_place(mut a []u32, b []u32) {
len_a := a.len
len_b := b.len
@ -221,8 +229,6 @@ fn subtract_in_place(mut a []u32, b []u32) {
carry = new_carry
}
} else { // if len.b > len.a return zero
for a.len > 0 {
a.delete_last()
}
a.clear()
}
}