【问题标题】:number of consecutive ones on the left side of an integer using only bit operations仅使用位运算的整数左侧的连续个数
【发布时间】:2014-02-20 06:25:20
【问题描述】:

如何仅使用 C 中的位运算(没有 if、for、while 等)返回整数左侧的连续个数? 我不知道从哪里开始解决这个问题。

//BurstSize(-1) = 32, 
//BurstSize(0xFFF0F0F0) = 12
//Legal: ! ~ & ^ | + << >>
//Max ops: 50
int BurstSize(int a) {
   //code 
}

【问题讨论】:

  • + 不是按位运算符
  • 不要在主题中输入整个问题
  • 在左侧,如果您指的是 MSB,那么您可能会陷入负数的陷阱。
  • 请举例说明您的要求
  • 输入的是二进制数吗?换句话说,我们只是在寻找 1 和 0 吗?

标签: c int bit-manipulation


【解决方案1】:

如果您使用 GCC,您可以调用 __builtin_clz() 来计算前导零。反转输入,然后它可以用来计算领先的。

int BurstSize(unsigned a) {
    return __builtin_clz(~a);
}

如果你不能访问__builtin_*(),那么你可以像Hacker's Delight那样实现前导零计数功能:

int nlz4(unsigned x) {
   int y, m, n;

   y = -(x >> 16);      // If left half of x is 0,
   m = (y >> 16) & 16;  // set n = 16.  If left half
   n = 16 - m;          // is nonzero, set n = 0 and
   x = x >> m;          // shift x right 16.
                        // Now x is of the form 0000xxxx.
   y = x - 0x100;       // If positions 8-15 are 0,
   m = (y >> 16) & 8;   // add 8 to n and shift x left 8.
   n = n + m;
   x = x << m;

   y = x - 0x1000;      // If positions 12-15 are 0,
   m = (y >> 16) & 4;   // add 4 to n and shift x left 4.
   n = n + m;
   x = x << m;

   y = x - 0x4000;      // If positions 14-15 are 0,
   m = (y >> 16) & 2;   // add 2 to n and shift x left 2.
   n = n + m;
   x = x << m;

   y = x >> 14;         // Set y = 0, 1, 2, or 3.
   m = y & ~(y >> 1);   // Set m = 0, 1, 2, or 2 resp.
   return n + 2 - m;
}

int BurstSize(unsigned a) {
   return nlz4(~a);
}

【讨论】:

  • 这听起来像是作弊:-)
  • @leeduhem 编辑了我的答案,所以这不是作弊。
  • 这个好多了。
  • 感谢这适用于未签名的整数,现在我需要尝试使其适用于已签名的整数
  • @donth2934 - 不要尝试对有符号整数进行位操作。如果您只是将一个有符号整数分配给一个无符号变量,那么一切都会奏效。
【解决方案2】:

最简单的方法:反转数字,然后找到最高有效位集。其余的你可以自己做(我 99% 确定这是一个家庭作业问题,所以我只是给出一个提示。如果你真的需要更多帮助,请在 cmets 中提问,我会进一步扩展)。

至于寻找最高有效位集合,请看https://stackoverflow.com/a/21413883/1967396

一个相当有效的方法。

更新现在找到一个完整的方法,找到最高有效位集(在反转之后),然后使用一个聪明的查找表转换为实际字节(使用模 37 技巧,它没有来自我...我在http://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightModLookup 找到它,但做了一个小改动,所以它适用于 32 位设置)。我包含用于测试 0 到 32 位模式的代码 - 似乎可行。

#include <stdio.h>

int burstSize(int n) {
 // return number of consecutive bits set
 unsigned int m, r;
 m = ~n;
 m = m | m >> 1;
 m = m | m >> 2;
 m = m | m >> 4;
 m = m | m >> 8;
 m = m | m >> 16;
 m = ((m ^ (m >> 1)) | 0x80000000) & m;
static const int Mod37BitPosition[] = // map a bit value mod 37 to its position
{
  -1, 0, 1, 26, 2, 23, 27, 0, 3, 16, 24, 30, 28, 11, 0, 13, 4,
  7, 17, 0, 25, 22, 31, 15, 29, 10, 12, 6, 0, 21, 14, 9, 5,
  20, 8, 19, 18
};
r = Mod37BitPosition[m % 37]; // <<<< not sure if this is allowed in your assignment...
return 31 - r; // <<< you could rewrite the LUT so you don't need an operation here. I was lazy.
}

int main(void) {
  printf("%d\n", burstSize(0x00000000));
  printf("%d\n", burstSize(0x80000000));
  printf("%d\n", burstSize(0xC0000000));
  printf("%d\n", burstSize(0xE0000000));
  printf("%d\n", burstSize(0xF0000000));
  printf("%d\n", burstSize(0xF8000000));
  printf("%d\n", burstSize(0xFC000000));
  printf("%d\n", burstSize(0xFE000000));
  printf("%d\n", burstSize(0xFF000000));
  printf("%d\n", burstSize(0xFF800000));
  printf("%d\n", burstSize(0xFFC00000));
  printf("%d\n", burstSize(0xFFE00000));
  printf("%d\n", burstSize(0xFFF00000));
  printf("%d\n", burstSize(0xFFF80000));
  printf("%d\n", burstSize(0xFFFC0000));
  printf("%d\n", burstSize(0xFFFE0000));
  printf("%d\n", burstSize(0xFFFF0000));
  printf("%d\n", burstSize(0xFFFFF800));
  printf("%d\n", burstSize(0xFFFFFC00));
  printf("%d\n", burstSize(0xFFFFFE00));
  printf("%d\n", burstSize(0xFFFFFF00));
  printf("%d\n", burstSize(0xFFFFFFF8));
  printf("%d\n", burstSize(0xFFFFFFFC));
  printf("%d\n", burstSize(0xFFFFFFFE));
  printf("%d\n", burstSize(0xFFFFFFFF));
}

【讨论】:

  • 谢谢,我会尝试使用它
【解决方案3】:

试试这个:

unsigned int A=0XFFF0; //your own number
    unsigned int B0=(1 & A)/1;
    unsigned int B1=(2 & A)/2;
    unsigned int B2=(4 & A)/4;
    unsigned int B3=(8 & A)/8;
    unsigned int B4=(16 & A)/16;
    unsigned int B5=(32 & A)/32;
    unsigned int B6=(64 & A)/64;
    unsigned int B7=(128 & A)/128;
    unsigned int B8=(256 & A)/256;
    unsigned int B9=(512 & A)/512;
    unsigned int B10=(1024 & A)/1024;
    unsigned int B11=(2048 & A)/2048;
    unsigned int B12=(4096 & A)/4096;
    unsigned int B13=(8192 & A)/8192;
    unsigned int B14=(16384 & A)/16384;
    unsigned int B15=(32768 & A)/32768;

    int  Result=B15+
                B14*(B15)+
                B13*(B14*B15)+
                B12*(B13*B14*B15)+
                B11*(B12*B13*B14*B15)+
                B10*(B11*B12*B13*B14*B15)+
                B9*(B10*B11*B12*B13*B14*B15)+
                B8*(B9*B10*B11*B12*B13*B14*B15)+
                B7*(B8*B9*B10*B11*B12*B13*B14*B15)+
                B6*(B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B5*(B6*B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B4*(B5*B6*B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B3*(B4*B5*B6*B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B2*(B3*B4*B5*B6*B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B1*(B2*B3*B4*B5*B6*B7*B8*B9*B10*B11*B12*B13*B14*B15)+
                B0*(B1*B2*B3*B4*B5*B6*B7*B8*B9*B10*B11*B12*B13*B14*B15);

【讨论】:

  • 不够...输入是 32 位长。
  • 标准 C int 类型为 16 位,新编译器为 32 位
  • 问题要求连续 - 这个答案是“计算所有的”
  • @Floris 我告诉他可以使用这个想法,所以我更正了!谢谢你告诉我这个问题。
  • 错了,C 没有指定任何大小,它只是保证 int 至少有 16 位。 CHAR_BIT = 9、24 或 32 的系统如何具有 16 位整数?这些系统并非不存在
【解决方案4】:

以下答案将数字反转来进行运算,它不使用% 运算符,但它使用一个- 符号:

#include <iostream>

int burstSize(int n) {
    // Reverse the bits
    n = (n & 0x55555555) <<  1 | (n & 0xAAAAAAAA) >>  1; 
    n = (n & 0x33333333) <<  2 | (n & 0xCCCCCCCC) >>  2; 
    n = (n & 0x0F0F0F0F) <<  4 | (n & 0xF0F0F0F0) >>  4; 
    n = (n & 0x00FF00FF) <<  8 | (n & 0xFF00FF00) >>  8; 
    n = (n & 0x0000FFFF) << 16 | (n & 0xFFFF0000) >> 16; 

    // rightmost 0-bit, produces 0 if none (e.g., 10100111 -> 00001000)
    int r = ~n & (n + 1);

    // r - 1 will give us a mask of the consequtive 1s to isolate (e.g., 0100 -> 0011)
    n = (r - 1) & n;

    // Count the bits  
    n = (n & 0x55555555) + ((n >> 1) & 0x55555555); 
    n = (n & 0x33333333) + ((n >> 2) & 0x33333333); 
    n = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F); 
    n = (n & 0x00FF00FF) + ((n >> 8) & 0x00FF00FF); 
    n = (n & 0x0000FFFF) + ((n >>16) & 0x0000FFFF);     

    // Return the bit count
    return n;
}

int main() {
    std::cout << burstSize(0x00000000) << std::endl; // 0 
    std::cout << burstSize(0x00010F00) << std::endl; // 0 
    std::cout << burstSize(0x80010F00) << std::endl; // 1     
    std::cout << burstSize(0xF0010F00) << std::endl; // 4
    std::cout << burstSize(0xFFFFFFFE) << std::endl; // 31
    std::cout << burstSize(0xFFFFFFFF) << std::endl; // 32
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-22
    相关资源
    最近更新 更多