Algorithms for counting digits

In algore library are some algorithms for counting the digits of a number.

The algorithms code is based on following sources:

Tested with zig version 0.13.0 on Linux Fedora 39.

:pushpin: 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

:pushpin: 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.

:eight_pointed_black_star: .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.

:eight_pointed_black_star: .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

:pushpin: 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);
}
2 Likes