使用仅按位运算符创建一个标记最重要设置位的掩码

时间:2014-01-28 18:16:02

标签: c bit-manipulation

这是昨晚应该给我的大型编程作业的一部分。无法弄清楚这个问题,但我很好奇它是如何解决的。

函数int greatestBitPos(int x)应该返回一个标记最高位的位置的int掩码。如果x == 0,则返回0.没有控制结构(if,while,?:)允许。

示例:greatestBitPos(96) = 0x40

合法经营者:! 〜& ^ | +<< >> =

This website on bit twiddling是我用作起点的东西,尤其是第二种算法。但是,它使用<比较,这个问题不允许。

欢迎所有想法,谢谢!

编辑:请假设2的补码,32位整数。对于所有负数,它们的最高位设置为,因此返回值应为0x80000000

5 个答案:

答案 0 :(得分:13)

更新为负数工作(假设这应该返回0x80000000,因为这些数字的顶部位已设置)

int gbp(int n) {
 // return log(2) of n
 unsigned int m;
 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);
printf("m is now %d\n", m);
return m;
}

说明:

从任何位模式开始,当我们向右移动1并取OR时,相邻位将变为1.示例

00010100
00001010
--------
00011110

你重复此操作,直到你在前导数字的右边都有一个,通过连续移动2,4,8,16(如果你有32位数字;对于更大的int你继续前进)。 / p>

最后你需要通过反转数字来“去掉所有其他的”,右移1,并取下AND:

00011111 AND 11110000 = 00010000

你有它。

对于负数,最终操作可确保您不会杀死最高位(如果存在)。如果你想用负数做其他事情,请告诉我它是什么。

答案 1 :(得分:3)

通过移位和OR运算将所有位填充到最重要的位:

0b 0010 0000 0000 0000 0100 0000 0000 0000
0b 0011 0000 0000 0000 0110 0000 0000 0000
0b 0011 1100 0000 0000 0111 1000 0000 0000
0b 0011 1111 1100 0000 0111 1111 1000 0000
0b 0011 1111 1111 1111 1111 1111 1111 1111

然后向右移动并添加1以留下最重要的一个:

0b 0001 1111 1111 1111 1111 1111 1111 1111
0b 0010 0000 0000 0000 0000 0000 0000 0000

代码:

int greatestBitPos(int x) {
  int is_nonzero = (x != 0);
  x = x | (x >> 1);
  x = x | (x >> 2);
  x = x | (x >> 4);
  x = x | (x >> 18);
  x = x | (x >> 16);
  return (is_nonzero * ((x >> 1) + 1));
}

答案 2 :(得分:0)

我仍然有兴趣看看其他人能想出什么,但是一位朋友已经找到了答案。

int greatestBitPos(int x) {
  int a = x | (x >> 1);
  a = a | (a >> 2);
  a = a | (a >> 4);
  a = a | (a >> 8);
  a = a | (a >> 16);
  return ((a ^ (a >> 1)) | 0x80 << 24) & a;
}

知道如果我们可以将MSB右边的所有位设置为1,那么只需设置MSB就可以了,而不是其他位。这个答案也适用于否定(关于二元补语)。

答案 3 :(得分:0)

事实上,你可以使用那里提到的第二个算法,稍作修改:

b形式为0 n 1 m

的特殊情况下
(a > b) == !!(a & ~b)

成立。

答案 4 :(得分:0)

assign a_reversed = {<<{a}};
assign a_2s_compl = (~a_reversed) + 1'b1;
assign a_lsb_set  = a_reversed & a_2s_compl;
assign a_msb_set  = {<<{a_lsb_set}};

这可以在一行和一个可参数化的函数中完成,但我已经在这里完成所有步骤以明确显示每一步发生的事情。