![](/img/trans.png)
[英]How to find the position of the only-set-bit in a 64-bit value using bit manipulation efficiently?
[英]find ones position in 64 bit number
我试图在64位数字中找到两个1的位置。 在这种情况下,那些位于第0和第63位置。 这里的代码返回0和32,这只是对齐的一半。 为什么这不起作用?
#include<stdio.h>
void main()
{
unsigned long long number=576460752303423489;
int i;
for (i=0; i<64; i++)
{
if ((number & (1 << i))==1)
{
printf("%d ",i);
}
}
}
线路上有两个漏洞
if ((number & (1 << i))==1)
哪个应该读
if (number & (1ull << i))
将1
更改为1ull
意味着左移是在unsigned long long
类型而不是int
,因此位掩码实际上可以到达位置32到63.将比较删除为1是因为number & mask
的结果(其中mask
只有一位设置)是mask
或0
,当i为0时mask
仅等于1。
但是,当我进行更改时,我的输出为0 59
,这仍然不是您所期望的。 剩下的问题是576460752303423489(十进制)= 0800 0000 0000 0001
(十六进制)。 0 59
是该数字的正确输出。 您想要的号码是9223372036854775809(十进制)= 8000 0000 0000 0001
(十六进制)。
顺便说一句, main
需要返回int
,而不是void
,并且需要显式return 0;
作为它的最后一个动作(除非你使用返回代码做一些更复杂的事情)。 是的,C99让你省略。 无论如何要这样做。
因为(1 << i)
是您正在编译和运行的平台上的32位int
值。 这然后得到符号扩展到64位的&
操作与所述number
值,从而导致位31至63被复制成位32。
此外,您正在将&
的结果&
1进行比较,这是不正确的。 如果该位置位则不为0,但不会为1。
将32位int移位32是未定义的。
此外,您的输入数字不正确。 设置的位位于0和59位(如果您希望从1开始计数,则为1和60)。
修复是使用(1ull << i),或以其他方式右移原始值和&
它为1(而不是左移1)。 当然,如果你用左移1和&
它与原始值,结果将不是1(除了位0),所以你需要比较!= 0
而不是== 1
。
#include<stdio.h>
int main()
{
unsigned long long number = 576460752303423489;
int i;
for (i=0; i<64; i++)
{
if ((number & (1ULL << i))) //here
{
printf("%d ",i);
}
}
}
首先是使用1ULL
来表示unsigned long long
常量。 第二个是在if
语句中,你的意思是不与1
进行比较,这对于最右边的位只会是真的。
输出: 0 59
这是正确的,因为576460752303423489
等于0x800000000000001
通过采用将>>
运算符应用于变量而不是文字的方法,首先可以避免这个问题:
if ((variable >> other_variable) & 1)
...
我知道这个问题有一些时间和多个正确的答案,而我应该是一个评论,但它有点太长了。 我建议你在宏中封装位检查逻辑,不要直接使用64号,而是计算它。 看一下相当全面的位操作黑客来源。
#include<stdio.h>
#include<limits.h>
#define CHECK_BIT(var,pos) ((var) & (1ULL<<(pos)))
int main(void)
{
unsigned long long number=576460752303423489;
int pos=sizeof(unsigned long long)*CHAR_BIT-1;
while((pos--)>=0) {
if(CHECK_BIT(number,pos))
printf("%d ",pos);
}
return(0);
}
可以使用编译器工具以最有效的方式执行位分析任务(在许多情况下仅使用单个CPU指令),而不是诉诸位操作。
例如,gcc和clang提供了那些方便的例程:
__builtin_popcountll() - number of bits set in the 64b value
__builtin_clzll() - number of leading zeroes in the 64b value
__builtin_ctzll() - number of trailing zeroes in the 64b value
__builtin_ffsll() - bit index of least significant set bit in the 64b value
其他编译器具有类似的机制。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.