C++ 20为你添加了两个新的库特征,比如“比特旋转和计数函数”和“两个操作的积分幂”。大多数添加的函数模板都是简单的数值实用函数,少数模板直接映射到现代CPU上的常见指令。我们已经在VisualStudio2019版本16.8预览版2中实现了它们。这篇文章将告诉您我们的实现以及您可以期望的特定于处理器的优化。
所有函数都是完全启用constexpr的,这对于计算查找表之类的事情应该非常方便。我知道我见过这些函数在几个数字代码基中实现,所以希望有标准版本会有用。新功能包括:
它们分别计算左侧(从最高有效位到最低有效位)或右侧(从最低有效位到最高有效位)的零数。在x86和x64平台上,它们发出 LZCNT
和 TZCNT
分别说明。默认情况下,在运行时检查指令的可用性。这个 BSF
和 BSR
如果运行时检查失败,将使用指令。使用编译时省略运行时检查 /arch:AVX2
或者更高,因为所有支持AVX2的cpu也支持 LZCNT
和 TZCNT
. 在ARM和ARM64上 countl_zero
发出 CLZ
指令; countr_zero
不会发出任何关于 ARM
或 ARM64
在这个时候。
有趣的是, LZCNT
和 TZCNT
在x86和x64上有一些奇怪的指令编码;它们被编码为 REP BSF
和 REP BSR
. 在不支持rep的cpu上忽略rep前缀 LZCNT
或 TZCNT
. 这意味着 LZCNT
或 TZCNT
在一个不支持它们的CPU上仍然可以运行,但是 TZCNT
零和零的输出不正确 LZCNT
两者都将有错误的零输出,并返回从最低有效位开始的第一组位的索引,这与它在实际支持该指令的cpu上所做的相反。这不是一个非常有用的回退,当我们尝试在 <bit>
为了简化一些代码,它最终带来了更多的麻烦。
请注意,VisualStudioVersion16.8Preview 1包含一个与 LZCNT
仅支持bsr的CPU上的用法。这将在Visual Studio版本16.8预览版3中修复。
std::popcount
计算其输入中的设置位数。在x86和x64平台上 popcount
发出 POPCNT
再次检查 POPCNT
在运行时。如果编译时使用 /arch:AVX
或更高版本,因为所有支持AVX的cpu也支持 POPCNT
. 此时不会在ARM或ARM64上发出特殊指令。
计算输入左侧或右侧的个数;这些依赖于 countl_zero
和 countr_zero
因此将使用与
功能等同于 popcount(x) == 1
. has_single_bit
不使用任何特殊说明。
查找输入上方或下方两个最近的幂。如果输入已经是2的幂,则返回时保持不变。如果结果不能在输入的类型中表示,那么行为是未定义的(例如在 bit_ceil(static_cast<unsigned char>(0b11111111))
). bit_ceil
仅当未发生此未定义行为时才允许作为常量表达式。 bit_floor
当输入为零时返回零。
按位向左或向右旋转输入。目前,这并没有显式地发出任何特殊指令。
今天你可以通过下载来尝试所有这些功能 Visual Studio 2019版本16.8预览版2 并用 /std:c++latest
. 如果您在我们的库实现中发现任何bug,请在我们的 GitHub页面 . 请报告有关的任何其他Visual Studio问题 开发者社区 . 如有任何问题或建议,请随时与我们联系。
你也可以阅读我们的 参考文献 或者相关的C++论文 <bit>
: P0553R4:位操作 和 P0556R3:积分二次幂运算 .