AK: Fix off by one error in integral ceil_log2()

Previously, certain values of `ceil_log2(x)` would be 1 smaller than
`ceil(log2(x))`.
This commit is contained in:
Tim Ledbetter 2024-05-13 18:57:38 +01:00 committed by Andreas Kling
parent 29112f7365
commit d0d81e470e
Notes: sideshowbarker 2024-07-18 01:43:16 +09:00
2 changed files with 36 additions and 4 deletions

View file

@ -27,12 +27,10 @@ constexpr T log2(T x)
template<Integral T> template<Integral T>
constexpr T ceil_log2(T x) constexpr T ceil_log2(T x)
{ {
if (!x) if (x <= 1)
return 0; return 0;
T log = AK::log2(x); return AK::log2(x - 1) + 1;
log += (x & ((((T)1) << (log - 1)) - 1)) != 0;
return log;
} }
template<Integral I> template<Integral I>

View file

@ -64,3 +64,37 @@ TEST_CASE(exp2)
EXPECT_EQ(AK::exp2<i64>(62), 4611686018427387904); EXPECT_EQ(AK::exp2<i64>(62), 4611686018427387904);
EXPECT_EQ(AK::exp2<u64>(63), 9223372036854775808ull); EXPECT_EQ(AK::exp2<u64>(63), 9223372036854775808ull);
} }
TEST_CASE(ceil_log2)
{
EXPECT_EQ(AK::ceil_log2<u64>(0), 0ull);
EXPECT_EQ(AK::ceil_log2<u64>(1), 0ull);
EXPECT_EQ(AK::ceil_log2<u8>(2), 1);
EXPECT_EQ(AK::ceil_log2<u8>(3), 2);
EXPECT_EQ(AK::ceil_log2<u8>(6), 3);
EXPECT_EQ(AK::ceil_log2<i8>(96), 7);
EXPECT_EQ(AK::ceil_log2<i8>(127), 7);
EXPECT_EQ(AK::ceil_log2<u8>(128), 7);
EXPECT_EQ(AK::ceil_log2<u8>(255), 8);
EXPECT_EQ(AK::ceil_log2<i16>(256), 8);
EXPECT_EQ(AK::ceil_log2<i16>(257), 9);
EXPECT_EQ(AK::ceil_log2<i16>(384), 9);
EXPECT_EQ(AK::ceil_log2<i16>(24576), 15);
EXPECT_EQ(AK::ceil_log2<i16>(32767), 15);
EXPECT_EQ(AK::ceil_log2<i32>(32768), 15);
EXPECT_EQ(AK::ceil_log2<i32>(32769), 16);
EXPECT_EQ(AK::ceil_log2<i32>(98304), 17);
EXPECT_EQ(AK::ceil_log2<i32>(1610612736), 31);
EXPECT_EQ(AK::ceil_log2<i32>(2147483647), 31);
EXPECT_EQ(AK::ceil_log2<u32>(2147483648), 31u);
EXPECT_EQ(AK::ceil_log2<u32>(2147483649), 32u);
EXPECT_EQ(AK::ceil_log2<u32>(3221225472), 32u);
EXPECT_EQ(AK::ceil_log2<u32>(4294967295), 32u);
EXPECT_EQ(AK::ceil_log2<i64>(4294967296), 32);
EXPECT_EQ(AK::ceil_log2<i64>(4294967297), 33);
EXPECT_EQ(AK::ceil_log2<i64>(9223372036854775807), 63ll);
EXPECT_EQ(AK::ceil_log2<u64>(9223372036854775808ull), 63ull);
EXPECT_EQ(AK::ceil_log2<u64>(9223372036854775809ull), 64ull);
EXPECT_EQ(AK::ceil_log2<u64>(13835058055282163712ull), 64ull);
EXPECT_EQ(AK::ceil_log2<u64>(18446744073709551615ull), 64ull);
}