11module big
22
3+ import math
34import math.bits
5+ import strings
46
57const 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
617pub const digit_bits = 60 // 60bits
718const 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`.
259283pub 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`.
854899pub 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