【问题标题】:Counting number of 1 bits in C++ negative number计算 C++ 负数中 1 的位数
【发布时间】:2015-11-20 09:09:12
【问题描述】:

如下函数:

int numOnesInBinary(int number) {
    int numOnes = 0;
    while (number != 0) {
        if ((number & 1) == 1) {
            numOnes++;
        }
        number >>= 1;
    }
    return numOnes;
}

只适用于正数,因为在负数的情况下,它总是在执行 >> 操作时将最左边的位加 1。在 Java 中我们可以使用 >>> 来代替,但是我们如何在 C++ 中做到这一点呢? 我在一本书中读到我们可以在 C++ 中使用无符号整数,但我不明白为什么无符号整数不能表示负数。

【问题讨论】:

  • 这是一个关于 C/C++ 的问题,所以这里离题了。
  • 这是一个需要调用 C++ 实现的未定义行为的问题,因此只有该特定架构的编译器编写者才能回答。全面的 SE 题外话...
  • 这不是题外话吗?
  • 您不需要它来保存值并因此表示负值,您只需要保留位模式。
  • 问题没有明确定义。 -1 中有多少个 1 位? -1 的正确答案是什么?无穷大?

标签: c++ bit-manipulation bitcount


【解决方案1】:

number 转换为 unsigned int 并对其进行计数:

int numOnesInBinary(int number) {
    int numOnes = 0;
    unsigned int unumber = static_cast<unsigned int>(number);
    while (unumber != 0) {
        if ((unumber & 1) == 1) {
            numOnes++;
        }
        unumber >>= 1;
    }
    return numOnes;
}

【讨论】:

  • @ÍhorMé 您的编辑并没有带来任何实际的性能改进:godbolt.org/z/H9G7UX。它只会使代码更难理解。请不要进行此类编辑。
  • 更高效的循环:while (unumber != 0) { numOnes += unumber &amp; 1; unumber &gt;&gt;= 1;}while (unumber != 0) { numOnes++; unumber &amp;= unumber - 1; }
  • @chqrlie 我的评论针对的是建议此编辑的用户:stackoverflow.com/review/suggested-edits/22475520。不知道你在告诉我什么。
  • @idmean:对不起,我误读了你的评论,不知道上下文。正如我单独建议的那样,ÍhorMé 的编辑确实应该是一个评论。
【解决方案2】:
// How about this method, as hinted in "C Book" by K & R.
// Of course better methods are found in MIT hackmem   
// http://www.inwap.com/pdp10/hbaker/hakmem/hakmem.html  
//
int numOnesInBinary(int number) {
    int numOnes = 0;
    // Loop around and repeatedly clear the LSB by number &= (number -1).  
    for (; number; numOnes++, number &= (number -1));
    return numOnes;
}

【讨论】:

  • number - 1 如果n 的值为INT_MIN,则调用未定义的行为。
【解决方案3】:

无符号整数可以在一个简单的循环中计算位数。

如果我们谈论值,从有符号转换为无符号会产生无效结果:

char c = -127;
unsigned char u = (unsigned char)c; // 129

但如果我们只谈论形式,它并没有改变:

1 0 0 0 0 0 0 1 == decimal signed -127
1 0 0 0 0 0 0 1 == decimal unsigned 129

所以转换为 unsigned 只是一个 hack。

【讨论】:

    【解决方案4】:

    count 表示整数 n 中设置的位数 如果整数的大小是 32 位,那么

    int count =0;  
    
    int n = -25 //(given)
    for(int k=0;k<32;k++){
         if ((n >> k) & 1){
            count++;
         }
    }
    
    return  count;
    

    【讨论】:

    • 恐怕n &gt;&gt; k 对否定n 具有实现定义的行为。此外,如果 int 类型少于 32 位,则行为未定义,如果 int 类型大于 32 位,则行为对于正值不正确......您的方法不能以可移植方式解决问题。跨度>
    • @chqrlie n>>k 在 n 为负时定义,因为负值被存储为 2 的补码,并且代码对于负整数工作正常。值 32 对应于用户可以根据数据类型相应设置的位数,在我的情况下,我将整数设为 32 位(尽管它取决于机器)。
    • C17 6.5.7 位移位运算符 E1 &gt;&gt; E2 的结果是E1 右移E2 位位置。如果E1 具有无符号类型,或者E1 具有带符号类型和非负值,则结果的值是E1/2^E2 的商的整数部分。如果E1 具有带符号类型和负值,则结果值是实现定义的。 即使可以断言负值表示为 2 的补码,标准也没有强制要求右移的语义. OP 没有指定 int 也有 32 位。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 2023-04-03
    • 2012-09-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多