diff options
| author | Jeroen van Rijn <Kelimion@users.noreply.github.com> | 2024-08-19 02:36:05 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-19 02:36:05 +0200 |
| commit | 17eb0b5ee0272ee53de06e1769f248d7ba034005 (patch) | |
| tree | c05c02345714da3af4d69843c244c63a5be8dbc5 | |
| parent | 359a212a78b56589cf9b38e4ebd8ef00c9f427a2 (diff) | |
| parent | b49b80bdf9f11c73e8b9dd4e2808c56c66584974 (diff) | |
Merge pull request #4107 from Feoramund/add-digit-count
Add `core:math.count_digits_of_base`
| -rw-r--r-- | core/math/math.odin | 30 | ||||
| -rw-r--r-- | tests/core/math/test_core_math.odin | 36 |
2 files changed, 65 insertions, 1 deletions
diff --git a/core/math/math.odin b/core/math/math.odin index 3d0ab3c4e..957e1672b 100644 --- a/core/math/math.odin +++ b/core/math/math.odin @@ -2443,6 +2443,36 @@ hypot :: proc{ hypot_f64, hypot_f64le, hypot_f64be, } +@(require_results) +count_digits_of_base :: proc "contextless" (value: $T, $base: int) -> (digits: int) where intrinsics.type_is_integer(T) { + #assert(base >= 2, "base must be 2 or greater.") + + value := value + when !intrinsics.type_is_unsigned(T) { + value = abs(value) + } + + when base == 2 { + digits = max(1, 8 * size_of(T) - int(intrinsics.count_leading_zeros(value))) + } else when intrinsics.count_ones(base) == 1 { + free_bits := 8 * size_of(T) - int(intrinsics.count_leading_zeros(value)) + digits, free_bits = divmod(free_bits, intrinsics.constant_log2(base)) + if free_bits > 0 { + digits += 1 + } + digits = max(1, digits) + } else { + digits = 1 + base := cast(T)base + for value >= base { + value /= base + digits += 1 + } + } + + return +} + F16_DIG :: 3 F16_EPSILON :: 0.00097656 F16_GUARD :: 0 diff --git a/tests/core/math/test_core_math.odin b/tests/core/math/test_core_math.odin index 2a752e366..8d51c9da0 100644 --- a/tests/core/math/test_core_math.odin +++ b/tests/core/math/test_core_math.odin @@ -2,6 +2,7 @@ package test_core_math import "core:math" +import "core:strconv" import "core:testing" @test @@ -1229,4 +1230,37 @@ test_large_tan :: proc(t: ^testing.T) { f2 := math.tan(vf[i] + large) testing.expectf(t, close(t, f1, f2), "math.tan(%.15g) = %.15g, want %.15g", vf[i]+large, f2, f1) } -}
\ No newline at end of file +} + +@test +test_count_digits :: proc(t: ^testing.T) { + _run_test :: proc(t: ^testing.T, $base: int) { + buf: [64]u8 + for n in 0..<i64(base*base*base) { + count := math.count_digits_of_base(n, base) + str := strconv.append_int(buf[:], n, base) + if !testing.expectf(t, + len(str) == count, + "decimal %i in base-%i digit count is %i, does not match length %i of %q", + n, base, count, len(str), str) { + break + } + } + } + + _run_test(t, 2) + _run_test(t, 3) + _run_test(t, 4) + _run_test(t, 5) + _run_test(t, 6) + _run_test(t, 7) + _run_test(t, 8) + _run_test(t, 9) + _run_test(t, 10) + _run_test(t, 11) + _run_test(t, 12) + _run_test(t, 13) + _run_test(t, 14) + _run_test(t, 15) + _run_test(t, 16) +} |