Add @intlog2 for Floored CT log-base2 (#2355)

* Add `@intlog2` for Floored CT log-base2
---------

Co-authored-by: Christoffer Lerno <christoffer@aegik.com>
This commit is contained in:
Zack Puhl
2025-08-02 16:53:36 -04:00
committed by GitHub
parent cb62554a26
commit e707190539
3 changed files with 36 additions and 0 deletions

View File

@@ -344,6 +344,23 @@ macro log(x, base)
*> *>
macro log2(x) => $$log2(values::promote_int(x)); macro log2(x) => $$log2(values::promote_int(x));
<*
@require values::@is_int($x) : `The input value must be an integer.`
@require $x >= 0 : `The input value must be a positive integer.`
@return `A floored base-2 log of an input integer value.`
*>
macro @intlog2($x)
{
$if $x <= 1:
return 0;
$endif
$typeof($x) $z = 0;
$for var $y = $x; $y > 0; $y >>= 1, ++$z: $endfor
return $z - 1;
}
<* <*
@require values::@is_promotable_to_floatlike(x) : `The input must be a number or a float vector` @require values::@is_promotable_to_floatlike(x) : `The input must be a number or a float vector`
*> *>

View File

@@ -4,6 +4,7 @@
### Changes / improvements ### Changes / improvements
- Support `alias foo = module std::io` module aliasing. - Support `alias foo = module std::io` module aliasing.
- Add compile-time `@intlog2` macro to math.
### Fixes ### Fixes
- List.remove_at would incorrectly trigger ASAN. - List.remove_at would incorrectly trigger ASAN.

View File

@@ -457,6 +457,24 @@ fn void test_log() @test
} }
} }
fn void test_ct_intlog2() @test @if($feature(SLOW_TESTS))
{
uint128 actual, expected;
$for var $x = 0; $x <= 128; ++$x :
expected = (uint128)math::floor(math::log2($x));
actual = (uint128)math::@intlog2($x);
assert(expected == actual, "input %d: floor(log2($x)) -> %d is not equal to @intlog2($x) -> %d", $x, expected, actual);
$endfor
var $logme = (uint128)1;
$for var $x = 0; $x < 8192; ++$x :
$logme *= 13;
expected = (uint128)math::floor(math::log2((uint128)$logme));
actual = (uint128)math::@intlog2((uint128)$logme);
assert(expected == actual, "input %d (idx %d): floor(log2(|$logme|)) -> %d is not equal to @intlog2(|$logme|) -> %d", $logme, $x, expected, actual);
$endfor
}
fn void test_pow() @test fn void test_pow() @test
{ {
int[<10>] e = { 2, 1, 0, -1, -2, 2, 1, 0, -1, -2 }; int[<10>] e = { 2, 1, 0, -1, -2, 2, 1, 0, -1, -2 };