C语言 仅使用位运算符创建标记最高有效集位的掩码

lrl1mhuk  于 2023-11-16  发布在  其他
关注(0)|答案(5)|浏览(133)

这是我昨晚交的一个较大的编程作业的一部分。我不能解决这个问题,但我很好奇如何解决它。
函数int greatestBitPos(int x)应该返回一个int掩码,标记最高有效位的位置。如果x==0,返回0。不允许使用控制结构(if,while,?:)。
示例:greatestBitPos(96) = 0x40
法律的运算符:!~ & ^|+ << >> =
这个网站上的bit twiddling是我用来作为起点的东西,特别是第二个算法。然而,它使用<比较,这是这个问题不允许的。
所有的想法都欢迎,谢谢!
编辑:请假设2的补码,32位整数。对于所有负数,它们的最高位设置,因此返回值应该是0x80000000

dgenwo3n

dgenwo3n1#

更新为适用于负数(假设这应该返回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


重复这个过程,直到前导数字的右边都是1,依次移动2、4、8、16(如果你有32位的数字;对于更大的int,你继续移动)。
最后,你需要通过反转数字,右移1,并取AND来“剥离所有其他的”:

00011111 AND 11110000 = 00010000


现在你看到了
对于负数,最后的操作确保你不会杀死最上面的一位,如果它存在的话。如果你想对负数做其他的事情,让我知道它是什么。

nom7f22z

nom7f22z2#

通过移位和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 >> 8);
  x = x | (x >> 16);
  return (is_nonzero * ((x >> 1) + 1));
}

huwehgph

huwehgph3#

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

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而不设置其他位就变得很容易了。这个答案也适用于负数(关于二进制补码)。

6ie5vjzr

6ie5vjzr4#

实际上,您可以使用此处提到的第二种算法,只需稍作修改:
b为0n1m形式的特殊情况下

(a > b) == !!(a & ~b)

字符串
保留。

ttp71kqs

ttp71kqs5#

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

字符串
这一切都可以在一行代码和一个可参数化的函数中完成,但我把所有步骤都放在这里,以显式地显示每一步都发生了什么。

相关问题