In algore library are some algorithms for counting the digits of a number.
The algorithms code is based on following sources:
- CodeMaze - What’s the Best Way to Count the Digits in a Number
- GitHub - Count Number of Digits in a Number
- Daniel Lemire’s blog - Computing the number of digits of an integer even faster
- GitHub - Code used on Daniel Lemire’s blog
Tested with zig version 0.13.0 on Linux Fedora 39.
About
Supported number types and ranges:
-
.ComptimeInt, .Int: ∓340282366920938463463374607431768211455
- min(i129) = -340282366920938463463374607431768211456 it is accepted to cover the type
-
.ComptimeFloat, .Float:
- comptime_float: ∓10384593717069655257060992658440193
- f16: ∓2049
- f32: ∓16777217
- f64: ∓9007199254740993
- f80: ∓36893488147419103234
- f128: ∓10384593717069655257060992658440193
Note that for float numbers, the type is important, for example 2050 as:
- f16: errors occur
- f32: returns 4, same as for any type greater than f16
Implementation
Functions internally convert the given number
to its absolute value, so that it can be used for both positive and negative numbers.
For numbers outside the ranges, errors occur.
.ComptimeInt and .Int numbers
Integer numbers are not restricted by their type, only by their value.
For consistency, the range of integers is limited to the values above, but some algorithms may work outside the range.
.ComptimeFloat and .Float numbers
Floating point numbers are restricted by their type and value.
The values above, for float ranges, are the first number whose integer part cannot be exactly represented by the float type.
For example, the first number for f16 is 2049, represented not exactly as 2048.
If only the number of digits matters, the limits can be extended for certain algorithms, but again for consistency, these limits are used.
For example, for f16 type:
- 9995 (not exactly 9990) return 4 digits, good result
- 9996 (not exactly 10000) return 5 digits, bad result
Example
const std = @import("std");
const assert = std.debug.assert;
const result = @import("algore").countDigitIterative;
// const result = @import("algore").countDigitLogarithmic;
// const result = @import("algore").countDigitLookup;
// const result = @import("algore").countDigitRecursive;
// const result = @import("algore").countDigitStringify;
// const result = @import("algore").countDigitSwitcher;
pub fn main() !void {
assert(result(0) == 1);
assert(result(0.0) == 1);
assert(result(@as(u32, 0)) == 1);
assert(result(@as(f32, 0.0)) == 1);
assert(result(1_000_000) == 7);
assert(result(-1_000_000) == 7);
assert(result(1_000_000.0) == 7);
assert(result(-1_000_000.0) == 7);
assert(result(@as(u256, 1_000_000)) == 7);
assert(result(@as(i256, -1_000_000)) == 7);
assert(result(@as(i32, 1_000_000)) == 7);
assert(result(@as(i32, -1_000_000)) == 7);
assert(result(@as(f32, 1_000_000.0)) == 7);
assert(result(@as(f32, -1_000_000.0)) == 7);
assert(result(@as(f16, 1_000.0)) == 4);
assert(result(@as(f16, -1_000.0)) == 4);
// decimal: 97, 101
assert(result('a') == 2);
assert(result('e') == 3);
// decimal: 9889, 128175
assert(result('⚡') == 4);
assert(result('💯') == 6);
// decimal: 16, 75
assert(result('\x10') == 2);
assert(result('\x4B') == 2);
// decimal: 1000, 1114111
assert(result('\u{3E8}') == 4);
assert(result('\u{10FFFF}') == 7);
//# errors occur
// assert(result(std.math.maxInt(u129)) == 39);
// assert(result(@as(u129, std.math.maxInt(u129))) == 39);
// assert(result(std.math.minInt(i130)) == 39);
// assert(result(@as(i130, std.math.minInt(i130))) == 39);
// assert(result(@as(f16, 2050)) == 4);
// assert(result("2050") == 4);
// assert(result(@as([]const u8, "-2050")) == 4);
// assert(result(.{}) == 0);
// assert(result(.{0}) == 1);
// assert(result(.{0.0}) == 1);
// assert(result(.{'a'}) == 2);
// assert(result(true) == 0);
// assert(result(null) == 0);
// assert(result(void) == 0);
// assert(result(undefined) == 0);
}