diff --git a/vlib/math/math.v b/vlib/math/math.v index a3387e637f..0d0d7a56f9 100644 --- a/vlib/math/math.v +++ b/vlib/math/math.v @@ -42,25 +42,71 @@ pub fn degrees(radians f64) f64 { return radians * (180.0 / pi) } -// digits returns an array of the digits of n in the given base. -pub fn digits(_n int, base int) []int { - if base < 2 { - panic('digits: Cannot find digits of n with base $base') +[params] +pub struct DigitParams { + base int = 10 + reverse bool +} + +// digits returns an array of the digits of `num` in the given optional `base`. +// The `num` argument accepts any integer type (i8|i16|int|isize|i64), and will be cast to i64 +// The `base:` argument is optional, it will default to base: 10. +// This function returns an array of the digits in reverse order i.e.: +// Example: assert math.digits(12345, base: 10) == [5,4,3,2,1] +// You can also use it, with an explicit `reverse: true` parameter, +// (it will do a reverse of the result array internally => slower): +// Example: assert math.digits(12345, reverse: true) == [1,2,3,4,5] +pub fn digits(num i64, params DigitParams) []int { + // set base to 10 initially and change only if base is explicitly set. + mut b := params.base + if b < 2 { + panic('digits: Cannot find digits of n with base $b') } - mut n := _n + mut n := num mut sign := 1 if n < 0 { sign = -1 n = -n } + mut res := []int{} - for n != 0 { - res << (n % base) * sign - n /= base + if n == 0 { + // short-circuit and return 0 + res << 0 + return res } + for n != 0 { + next_n := n / b + res << int(n - next_n * b) + n = next_n + } + + if sign == -1 { + res[res.len - 1] *= sign + } + + if params.reverse { + res = res.reverse() + } + return res } +// count_digits return the number of digits in the number passed. +// Number argument accepts any integer type (i8|i16|int|isize|i64) and will be cast to i64 +pub fn count_digits(number i64) int { + mut n := number + if n == 0 { + return 1 + } + mut c := 0 + for n != 0 { + n = n / 10 + c++ + } + return c +} + // minmax returns the minimum and maximum value of the two provided. pub fn minmax(a f64, b f64) (f64, f64) { if a < b { diff --git a/vlib/math/math_test.v b/vlib/math/math_test.v index 14e6b3489f..816bb9fe01 100644 --- a/vlib/math/math_test.v +++ b/vlib/math/math_test.v @@ -914,14 +914,40 @@ fn test_lcm() { } fn test_digits() { - digits_in_10th_base := digits(125, 10) - assert digits_in_10th_base[0] == 5 - assert digits_in_10th_base[1] == 2 - assert digits_in_10th_base[2] == 1 - digits_in_16th_base := digits(15, 16) - assert digits_in_16th_base[0] == 15 - negative_digits := digits(-4, 2) - assert negative_digits[2] == -1 + // a small sanity check with a known number like 100, + // just written in different base systems: + assert digits(100, reverse: true) == [1, 0, 0] + assert digits(100, base: 2, reverse: true) == [1, 1, 0, 0, 1, 0, 0] + assert digits(100, base: 3, reverse: true) == [1, 0, 2, 0, 1] + assert digits(100, base: 4, reverse: true) == [1, 2, 1, 0] + assert digits(100, base: 8, reverse: true) == [1, 4, 4] + assert digits(100, base: 10, reverse: true) == [1, 0, 0] + assert digits(100, base: 12, reverse: true) == [8, 4] + assert digits(100, base: 16, reverse: true) == [6, 4] + assert digits(100, base: 20, reverse: true) == [5, 0] + assert digits(100, base: 32, reverse: true) == [3, 4] + assert digits(100, base: 64, reverse: true) == [1, 36] + assert digits(100, base: 128, reverse: true) == [100] + assert digits(100, base: 256, reverse: true) == [100] + + assert digits(1234432112344321) == digits(1234432112344321, reverse: true) + assert digits(1234432112344321) == [1, 2, 3, 4, 4, 3, 2, 1, 1, 2, 3, 4, 4, 3, 2, 1] + + assert digits(125, base: 10, reverse: true) == [1, 2, 5] + assert digits(125, base: 10).reverse() == [1, 2, 5] + + assert digits(15, base: 16, reverse: true) == [15] + assert digits(127, base: 16, reverse: true) == [7, 15] + assert digits(65535, base: 16, reverse: true) == [15, 15, 15, 15] + assert digits(-65535, base: 16, reverse: true) == [-15, 15, 15, 15] + + assert digits(-127) == [7, 2, -1] + assert digits(-127).reverse() == [-1, 2, 7] + assert digits(-127, reverse: true) == [-1, 2, 7] + + assert digits(234, base: 7).reverse() == [4, 5, 3] + + assert digits(67432, base: 12).reverse() == [3, 3, 0, 3, 4] } // Check that math functions of high angle values @@ -966,3 +992,21 @@ fn test_powi() { assert powi(0, -2) == -1 // div by 0 assert powi(2, -1) == 0 } + +fn test_count_digits() { + assert count_digits(-999) == 3 + assert count_digits(-100) == 3 + assert count_digits(-99) == 2 + assert count_digits(-10) == 2 + assert count_digits(-1) == 1 + assert count_digits(0) == 1 + assert count_digits(1) == 1 + assert count_digits(10) == 2 + assert count_digits(99) == 2 + assert count_digits(100) == 3 + assert count_digits(999) == 3 + // + assert count_digits(12345) == 5 + assert count_digits(123456789012345) == 15 + assert count_digits(-67345) == 5 +}