Skip to content

Commit d8d125b

Browse files
authored
math.big: restore and refactor str() and integer_from_string() (#25154)
1 parent 752eb5c commit d8d125b

1 file changed

Lines changed: 66 additions & 21 deletions

File tree

‎vlib/math/big/integer.v‎

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
module big
22

3+
import math
34
import math.bits
5+
import strings
46

57
const digit_array = '0123456789abcdefghijklmnopqrstuvwxyz'.bytes()
8+
// vfmt off
9+
const radix_options = {
10+
2: 59, 3: 37, 4: 29, 5: 25, 6: 23, 7: 21, 8: 19, 9: 18, 10: 18,
11+
11: 17, 12: 16, 13: 16, 14: 15, 15: 15, 16: 14, 17: 14, 18: 14,
12+
19: 14, 20: 13, 21: 13, 22: 13, 23: 13, 24: 13, 25: 12, 26: 12,
13+
27: 12, 28: 12, 29: 12, 30: 12, 31: 12, 32: 11, 33: 11, 34: 11,
14+
35: 11, 36: 11
15+
}
16+
// vfmt on
617
pub const digit_bits = 60 // 60bits
718
const max_digit = (u64(1) << digit_bits) - u64(1)
819
// big.Integer
@@ -240,13 +251,17 @@ fn integer_from_regular_string(characters string, radix u32) Integer {
240251

241252
mut result := zero_int
242253
radix_int := integer_from_u32(radix)
243-
244-
for index := start_index; index < characters.len; index++ {
245-
digit := characters[index]
246-
value := digit_array.index(digit)
247-
248-
result *= radix_int
249-
result += integer_from_int(value)
254+
pow := radix_options[int(radix)]
255+
radix_pow := radix_int.pow(u32(pow))
256+
for i := start_index; i < characters.len; i += pow {
257+
end := math.min(i + pow, characters.len)
258+
num_str := characters[i..end]
259+
if num_str.len == pow {
260+
result *= radix_pow
261+
} else {
262+
result *= radix_int.pow(u32(num_str.len))
263+
}
264+
result += integer_from_u64(regular_string_to_radix(num_str, radix))
250265
}
251266

252267
return Integer{
@@ -255,6 +270,15 @@ fn integer_from_regular_string(characters string, radix u32) Integer {
255270
}
256271
}
257272

273+
fn regular_string_to_radix(characters string, radix u32) u64 {
274+
mut result := u64(0)
275+
276+
for c in characters {
277+
result = result * radix + u64(digit_array.index(c))
278+
}
279+
return result
280+
}
281+
258282
// abs returns the absolute value of the integer `a`.
259283
pub fn (a Integer) abs() Integer {
260284
return if a.signum == 0 {
@@ -822,37 +846,58 @@ pub fn (integer Integer) radix_str(radix u32) string {
822846
if integer.signum == 0 || radix == 0 {
823847
return '0'
824848
}
825-
return integer.general_radix_str(radix)
849+
return integer.general_radix_str(int(radix))
826850
}
827851

828-
fn (integer Integer) general_radix_str(radix u32) string {
852+
fn (integer Integer) general_radix_str(radix int) string {
829853
$if debug {
830854
assert radix != 0
831855
}
832-
divisor := integer_from_u32(radix)
856+
divisor := integer_from_int(radix).pow(u32(radix_options[radix]))
833857

834858
mut current := integer.abs()
835-
mut new_current := zero_int
836859
mut digit := zero_int
837-
mut rune_array := []rune{cap: current.digits.len * 4}
860+
mut sb := strings.new_builder(integer.digits.len * radix_options[radix]) // XXX
861+
mut st := []string{cap: integer.digits.len * radix_options[radix]}
838862
for current.signum > 0 {
839-
new_current, digit = current.div_mod_internal(divisor)
840-
rune_array << digit_array[digit.int()]
841-
unsafe { digit.free() }
842-
unsafe { current.free() }
843-
current = new_current
863+
current, digit = current.div_mod_internal(divisor)
864+
st << general_str(current, digit, radix)
844865
}
845866
if integer.signum == -1 {
846-
rune_array << `-`
867+
sb.write_string('-')
868+
}
869+
for st.len > 0 {
870+
sb.write_string(st.pop())
871+
}
872+
return sb.str()
873+
}
874+
875+
fn general_str(quotient Integer, remainder Integer, radix int) string {
876+
if quotient.signum == 0 && remainder.signum == 0 {
877+
return '0'
847878
}
879+
divisor := integer_from_int(radix)
848880

849-
rune_array.reverse_in_place()
850-
return rune_array.string()
881+
mut current := remainder.abs()
882+
mut digit := zero_int
883+
mut sb := strings.new_builder(radix_options[radix])
884+
mut st := []u8{cap: radix_options[radix]}
885+
for current.signum > 0 {
886+
current, digit = current.div_mod_internal(divisor)
887+
st << digit_array[digit.int()]
888+
}
889+
if quotient.signum > 0 {
890+
sb.write_string(strings.repeat(48, radix_options[radix] - st.len))
891+
}
892+
for st.len > 0 {
893+
sb.write_u8(st.pop())
894+
}
895+
return sb.str()
851896
}
852897

853898
// str returns the decimal string representation of the integer `a`.
854899
pub fn (integer Integer) str() string {
855-
return integer.radix_str(10)
900+
return integer.radix_str(u32(10))
856901
}
857902

858903
// int returns the integer value of the integer `a`.

0 commit comments

Comments
 (0)