有效的逐位运算,用于计数位或查找最右边|最左边的位
Efficient bitwise operations for counting bits or find the right|left most ones
给定一个无符号的int,我必须实现以下操作:
- 计数设置为1的位数
- 查找最左边1位的索引
- 找到最右边的索引1位
(操作不应依赖于体系结构)。
我已经使用逐位移位完成了这项工作,但我必须遍历几乎所有的位(es.32)。例如,计数1:
unsigned int number= ...;
while(number != 0){
if ((number & 0x01) != 0)
++count;
number >>=1;
}
其他操作类似。
所以我的问题是:有没有更快的方法可以做到这一点?
如果您想要最快的方式,则需要使用不可移植的方法。
Windows/MSVC:
- _BitScanForward()
- _BitScanReverse()
- __popcnt()
GCC:
- __内置_ffs()
- __内置_ctz()
- __内置_clz()
- __内置_popcount()
这些通常直接映射到本机硬件指令。所以它不会比这些快多少。
但由于它们没有C/C++功能,因此只能通过编译器内部函数访问。
看看ffs(3),ffsl(3)、fls(3。
ffs()和ffsl()函数查找i中的第一个位集(从最低有效位开始),并返回该位的索引。
函数fls()和flsl()查找i中设置的最后一个位,并返回该位的索引。
您可能也对比特串(3)感兴趣。
引用http://graphics.stanford.edu/~seander/bithacks.html
对32位整数v中的位进行计数的最佳方法如下:
unsigned int v; // count bits set in this (32-bit value) unsigned int c; // store the total here v = v - ((v >> 1) & 0x55555555); // reuse input as temporary v = (v & 0x33333333) + ((v >> 2) & 0x33333333); // temp c = ((v + (v >> 4) & 0xF0F0F0F) * 0x1010101) >> 24; // count
最佳比特计数方法只需要12次操作,这与查找表方法相同,但避免了表的内存和潜在的缓存未命中。它是上面纯并行方法和早期使用乘法的方法(在关于用64位指令计数位的部分中)的混合,尽管它不使用64位指令。字节中设置的位的计数是并行进行的,并且通过乘以0x1010101并右移24位来计算字节中设置位的总和。
数字x的"最右边的1位"由给出
pos(1st '1') = log_2(x XOR (x-1) + 1) - 1
例如:
x = 1100101000;
x-1 = 1100100111;
x XOR (x-1) = 0000001111;
x XOR (x-1) + 1 = 0000010000;
最后一行的base2 log会给出正确的位置+1。因此,从日志结果中减去1,您将获得最正确的"1"位。
对于最右边的"0"位,您可以使用
pos(1st '0') = log_2(x XOR (x+1) + 1) - 1
使用C++20,这些操作可以通过新添加的头<bit>
轻松完成。
popcount
countl_one
countr_one
然后,它们中的每一个都将调用编译器特定的函数,如__popcnt()
和__builtin_popcount()
。
对于最右边的位简单ans
第一种方法
unsigned int getFirstSetBit(int n){
return log2(n & -n) + 1;
}
第二种方法
unsigned int getFirstSetBit(int n){
return ffs(n);
}
- 正在查找文档以获得PS4平台的C++中的设备信息
- 在C++中查找文件
- 模板元程序查找相似的连续类型名称
- 在UNIX系统中使用DIR查找文件的字节大小
- 查找最接近的大于当前数字的数字的索引
- 有没有一种方法可以创建一个带有哈希表的数据库,该哈希表具有恒定时间查找功能
- 查找后更改类变量
- 使用正则表达式regex_search在字符串中查找字符串
- 使用gcc从静态链接的文件中查找可选符号
- 在C++中查找范围的长度
- 算法问题:查找从堆栈中弹出的所有序列
- 在Windows中查找扬声器输出的当前音量级别
- 如何在C++中使用X509证书模在令牌中查找私钥
- 使用.find函数在c++中查找字符和另一个字符之间的大小
- 在 Windows 上,是否可以让 dll 在不使用 PATH 环境变量的情况下在另一个文件夹中查找依赖项?
- 在 for 循环中查找问题时遇到困难
- 如何在文件中查找字节序列
- 试图创建一个多线程程序来查找0-100000000之间的总素数
- 使用堆查找第K个最大元素的时间复杂性
- 有效的逐位运算,用于计数位或查找最右边|最左边的位