我有两种替代代码实现来计算小于给定 64 位无符号整数 (uint64_t) 的 2 的最大幂:
实施1:
#include <iostream>
#include <cstdint>
uint64_t floor_power_of_2(uint64_t x)
{
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
x |= (x >> 32);
return x - (x >> 1);
}
实现 2(我更喜欢它,因为速度要快得多):
#include <iostream>
#include <cstdint>
uint64_t floor_power_of_2(uint64_t x)
{
return 1ULL << (63 - __builtin_clzll(x));//63-count of leading zeros
}
我的问题是:
__builtin_clzll()
的可移植性:实现 2 的可移植性如何
跨不同的编译器、操作系统和 CPU
架构?它是否依赖于特定的CPU指令
不是到处都有吗?__builtin_clzll()
是否可用,以便程序
如果没有实现 2,可以使用实现 1 作为后备
支持吗?我目前使用的是 GCC 编译器,但我也用 Clang 在 Compiler Explorer 上进行了测试(它可以编译它,而且似乎比 gcc 做得更好)。
我有兴趣确保与各种平台的兼容性。
如果您对这些问题有任何见解或指导,我将不胜感激。
__builtin_clzll
是 GCC 内置的。从 GCC 派生的编译器和尝试与 GCC 兼容的编译器(例如 Clang)将支持它,但其他编译器不会或可能有自己的内置替代方案。
没有检测内置函数的标准方法。它们完全取决于实现(因为所有内容都包含双下划线)。您需要检查正在哪个编译器下进行编译。此任务可能更适合构建系统,但您可以使用 GCC 和 Clang 定义的
__GNUC__
宏。
在 C++20 中,
__builtin_clzll
的标准化已经作为 std::countl_zero
存在于标准库中,我希望标准库实现者能够以最有效的方式为他们支持的每个平台和编译器仔细实现它。
此外,标准库实现会自动在所有无符号整数类型上正确工作,并且它们的行为可预测地使用输入
0
,而您的第二个实现则不然,因为根据 GCC 文档,它对于输入 0
具有未定义的行为。
还有
std::bit_width
,它更直接地给出需要提升到2的幂的位数。然而,再次考虑一下,函数对于输入应该如何表现0
。
还有
std::bit_floor
,它与您要实现的函数类似,只不过它为输入提供了较小的 或等于 的最大幂。