简体   繁体   English

找到64位数的位置

[英]find ones position in 64 bit number

I'm trying to find the position of two 1's in a 64 bit number. 我试图在64位数字中找到两个1的位置。 In this case the ones are at the 0th and 63rd position. 在这种情况下,那些位于第0和第63位置。 The code here returns 0 and 32, which is only half right. 这里的代码返回0和32,这只是对齐的一半。 Why does this not work? 为什么这不起作用?

#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);

        }   
    }
}

There are two bugs on the line 线路上有两个漏洞

if ((number & (1 << i))==1)

which should read 哪个应该读

if (number & (1ull << i))

Changing 1 to 1ull means that the left shift is done on a value of type unsigned long long rather than int , and therefore the bitmask can actually reach positions 32 through 63. Removing the comparison to 1 is because the result of number & mask (where mask has only one bit set) is either mask or 0 , and mask is only equal to 1 when i is 0. 1更改为1ull意味着左移是在unsigned long long类型而不是int ,因此位掩码实际上可以到达位置32到63.将比较删除为1是因为number & mask的结果(其中mask只有一位设置)是mask0 ,当i为0时mask仅等于1。

However, when I make that change, the output for me is 0 59 , which still isn't what you expected. 但是,当我进行更改时,我的输出为0 59 ,这仍然不是您所期望的。 The remaining problem is that 576460752303423489 (decimal) = 0800 0000 0000 0001 (hexadecimal). 剩下的问题是576460752303423489(十进制)= 0800 0000 0000 0001 (十六进制)。 0 59 is the correct output for that number. 0 59是该数字的正确输出。 The number you wanted is 9223372036854775809 (decimal) = 8000 0000 0000 0001 (hex). 想要的号码是9223372036854775809(十进制)= 8000 0000 0000 0001 (十六进制)。

Incidentally, main is required to return int , not void , and needs an explicit return 0; 顺便说一句, main需要返回int ,而不是void ,并且需要显式return 0; as its last action (unless you are doing something more sophisticated with the return code). 作为它的最后一个动作(除非你使用返回代码做一些更复杂的事情)。 Yes, C99 lets you omit that. 是的,C99让你省略。 Do it anyway. 无论如何要这样做。

Because (1 << i) is a 32-bit int value on the platform you are compiling and running on. 因为(1 << i)是您正在编译和运行的平台上的32位int值。 This then gets sign-extended to 64 bits for the & operation with the number value, resulting in bit 31 being duplicated into bits 32 through 63. 这然后得到符号扩展到64位的&操作与所述number值,从而导致位31至63被复制成位32。

Also, you are comparing the result of the & to 1, which isn't correct. 此外,您正在将&的结果& 1进行比较,这是不正确的。 It will not be 0 if the bit is set, but it won't be 1. 如果该位置位则不为0,但不会为1。

Shifting a 32-bit int by 32 is undefined. 将32位int移位32是未定义的。

Also, your input number is incorrect. 此外,您的输入数字不正确。 The bits set are at positions 0 and 59 (or 1 and 60 if you prefer to count starting at 1). 设置的位位于0和59位(如果您希望从1开始计数,则为1和60)。

The fix is to use (1ull << i), or otherwise to right-shift the original value and & it with 1 (instead of left-shifting 1). 修复是使用(1ull << i),或以其他方式右移原始值和&它为1(而不是左移1)。 And of course if you do left-shift 1 and & it with the original value, the result won't be 1 (except for bit 0), so you need to compare != 0 rather than == 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);    
        }   
    }
}

First is to use 1ULL to represent unsigned long long constant. 首先是使用1ULL来表示unsigned long long常量。 Second is in the if statement, what you mean is not to compare with 1 , that will only be true for the rightmost bit. 第二个是在if语句中,你的意思是不与1进行比较,这对于最右边的位只会是真的。

Output: 0 59 输出: 0 59

It's correct because 576460752303423489 is equal to 0x800000000000001 这是正确的,因为576460752303423489等于0x800000000000001

The problem could have been avoided in the first place by adopting the methodology of applying the >> operator to a variable, instead of a literal: 通过采用将>>运算符应用于变量而不是文字的方法,首先可以避免这个问题:

if ((variable >> other_variable) & 1)
   ...

I know the question has some time and multiple correct answers while my should be a comment, but is a bit too long for it. 我知道这个问题有一些时间和多个正确的答案,而我应该是一个评论,但它有点太长了。 I advice you to encapsulate bit checking logic in a macro and don't use 64 number directly, but rather calculate it. 我建议你在宏中封装位检查逻辑,不要直接使用64号,而是计算它。 Take a look here for quite comprehensive source of bit manipulation hacks. 一下相当全面的位操作黑客来源。

#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);
}

Rather than resorting to bit manipulation, one can use compiler facilities to perform bit analysis tasks in the most efficient manner (using only a single CPU instruction in many cases). 可以使用编译器工具以最有效的方式执行位分析任务(在许多情况下仅使用单个CPU指令),而不是诉诸位操作。

For example, gcc and clang provide those handy routines: 例如,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

Other compilers have similar mechanisms. 其他编译器具有类似的机制。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM