如何检查 int 中是否恰好设置了一位?
How to check if exactly one bit is set in an int?
我有一个std::uint32_t
,想检查是否设置了一位。如何在不像这样遍历所有位的情况下执行此操作?换句话说,下面的功能可以简化吗?
static inline bool isExactlyOneBitSet(std::uint32_t bits)
{
return ((bits & 1) == bits
|| (bits & 1 << 1) == bits
|| (bits & 1 << 2) == bits
// ...
|| (bits & 1 << 31) == bits
);
}
奖励:如果返回值是找到的位或 0,那就太好了。
static inline bool isExactlyOneBitSet(std::uint32_t bits)
{
if (bits & 1) {return 1;}
else if (bits & 1 << 1) {return 1 << 1;};
//...
else if (bits & 1 << 31) {return 1 << 31;};
return 0;
}
所以你想知道一个数字是否是 2 的幂?嗯,有一个著名的算法,你可以简单地做,
check_bit(std::uint32_t bits)
{
return bits && !(bits & (bits-1));
}
2 的任何幂减去 1 都是1s
的,例如,
4 - 1 = 3 (011)
8 - 1 = 7 (0111)
按位和 2 的任何幂和任何数字 1 的幂小于它将给出0
.因此,我们可以通过使用表达式来验证一个数字是否为 2 的幂,n&(n-1)
.
n=0
时会失败,因此我们必须添加一个额外的and
条件。
要查找位的位置,您可以执行以下操作:
int findSetBit(std::uint32_t bits)
{
if (!(bits && !(bits & (bits-1))))
return 0;
return log2(bits) + 1;
}
额外的东西
在 gcc 中,您可以使用__builtin_popcount()
来查找任意数字的集合位计数。
#include <iostream>
int main()
{
std::cout << __builtin_popcount (4) << "n";
std::cout << __builtin_popcount (3) << "n";
return 0;
}
然后检查计数是否等于1
。
关于计数,还有另一种著名的算法,Brian Kernighan算法。谷歌一下,它会在log(n)
时间内找到计数。
这是您的奖金问题的解决方案(当然,这也是您原始问题的解决方案(:
std::uint32_t exactlyOneBitSet(std::uint32_t bits) {
return bits&(((bool)(bits&(bits-1)))-1);
}
这在带有 clang 的 x86_64 上编译为只有 4 条指令:
0000000000000000 <exactlyOneBitSet(unsigned int)>:
0: 8d 4f ff lea -0x1(%rdi),%ecx
3: 31 c0 xor %eax,%eax
5: 85 f9 test %edi,%ecx
7: 0f 44 c7 cmove %edi,%eax
a: c3 retq
C++20 有一个函数可以做到这一点:std::has_single_bit(value(。 它在标题<bit>
中。
给定一个数字n
,下面的表达式将确定是否只设置了一个位(在任何语言中(:(n & (n - 1)) == 0
。
要检查一个数字是否是 2 的精确幂,您还可以使用表达式(n & (-n)) == n
。
但是,在JavaScript 中,这些表达式在-2^31
时失败。
请注意此处的按位 AND (&
( 运算符。
相关文章:
- 一位朋友将模板函数缩写为clang和gcc
- 斐波那契数列部分和的最后一位数字
- 将第 n 个斐波那契数的大斐波那契数的最后一位编程.C++
- 只设置一次方法中变量的值
- 如何检查 int 中是否恰好设置了一位?
- 如何正确取消设置64位数字中的位?
- 如何找到由公式计算的非常大的数字的最后一位数字?
- 如何在 9 位整数中的所有"1"之后快速设置 64 位
- 为什么parse_config_file流上设置故障位
- 我如何使用十一位数字
- 确保静态成员最多设置一次 (C++)
- 在 C++ 中立即设置故障位(在读取任何字节之前)
- 如何基于用户设置的初始变量设置一组常数值
- 获取设置故障位的流位置 / std::ios::抛出故障
- 使用位操作将8字节数字中的每个字节中的一位转换为单个字节
- 标志-检查是否设置了位并且仅设置了这些位
- 我在spoj-lastdig2中使用我的代码 - 重新访问的最后一位数字
- IOstream哨兵在到达末尾时不会设置故障位
- 试图设置一个数组将最后三个存款存储到银行帐户系统中
- 寻求一种在 C++ 中设置 128 位或更高位集的方法