aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeroen van Rijn <Kelimion@users.noreply.github.com>2024-08-19 02:36:05 +0200
committerGitHub <noreply@github.com>2024-08-19 02:36:05 +0200
commit17eb0b5ee0272ee53de06e1769f248d7ba034005 (patch)
treec05c02345714da3af4d69843c244c63a5be8dbc5
parent359a212a78b56589cf9b38e4ebd8ef00c9f427a2 (diff)
parentb49b80bdf9f11c73e8b9dd4e2808c56c66584974 (diff)
Merge pull request #4107 from Feoramund/add-digit-count
Add `core:math.count_digits_of_base`
-rw-r--r--core/math/math.odin30
-rw-r--r--tests/core/math/test_core_math.odin36
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)
+}