C#从第一个有效位开始获取uint32的高4位

时间:2017-05-11 09:25:13

标签: c# bit-manipulation uint32

我的需求是 - 有一些(实际上伪)随机数uint32,我需要它的4个第一位用第1位表示,而不是0,例如。

  

... 000100101 => 1001

     

1000 ... 0001 => 1000

     

... 0001 => 0001

     

... 0000 => 0000

等 我明白我必须使用这样的东西

uint num = 1157 (some random number)
uint high = num >> offset

问题是 - 我不知道第一位在哪里所以我不能将>>用于常量变量。有人可以解释如何找到这个offset吗?

2 个答案:

答案 0 :(得分:2)

您可以先计算最高有效位(HSB)然后相应地移位。你可以这样:

int hsb = -4;
for(uint cnum = num; cnum != 0; cnum >>= 1, hsb++);
if(hsb < 0) {
    hsb = 0;
}
uint result = num >> hsb;

因此我们首先要检测最高设置位(或该指数减去4)的索引。我们通过递增hsb并将cnumnum的副本)向右移动来实现此目的,直到cnum中不再存在设置位。

接下来,我们确保有这样的设置位,并且它至少具有索引4(如果没有,则不执行任何操作)。结果是原始numhsb向右移动。

如果我在0x123上运行此操作,我会在0x9互动外壳中获得csharp

csharp> uint num = 0x123;
csharp> int hsb = -4;
csharp> for(uint cnum = num; cnum != 0; cnum >>= 1, hsb++);
csharp> if(hsb < 0) {
      >     hsb = 0;
      > }
csharp> uint result = num >> hsb;
csharp> result
9

0x123是二进制的0001 0010 0011。所以:

0001 0010 0011
   1 001

10019

答案 1 :(得分:2)

确定最重要的非零位的位置与计算基数2的对数相同。在现代CPU上快速执行此操作会有“位移技巧”:

int GetLog2Plus1(uint value)
{
    value |= value >> 1;
    value |= value >> 2;
    value |= value >> 4;
    value |= value >> 8;
    value |= value >> 16;
    value -= value >> 1 & 0x55555555;
    value = (value >> 2 & 0x33333333) + (value & 0x33333333);
    value = (value >> 4) + value & 0x0F0F0F0F;
    value += value >> 8;
    value += value >> 16;
    value &= 0x0000003F;
    return (int) value;
}

这将返回0到32之间的数字:

Value                                      | Log2 + 1
-------------------------------------------+---------
0b0000_0000_0000_0000_0000_0000_0000_0000U |        0
0b0000_0000_0000_0000_0000_0000_0000_0001U |        1
0b0000_0000_0000_0000_0000_0000_0000_0010U |        2
0b0000_0000_0000_0000_0000_0000_0000_0011U |        2
0b0000_0000_0000_0000_0000_0000_0000_0100U |        3
...
0b0111_1111_1111_1111_1111_1111_1111_1111U |       31
0b1000_0000_0000_0000_0000_0000_0000_0000U |       32
0b1000_0000_0000_0000_0000_0000_0000_0001U |       32
...                                        |
0b1111_1111_1111_1111_1111_1111_1111_1111U |       32

(Math nitpickers会注意到0的对数是未定义的。但是,我希望上面的表格能够说明如何处理这个问题并对这个问题有意义。)

然后,如果值小于8(其中log2 + 1为&lt; 4),则可以计算最重要的非零位,并考虑到您需要4个最低有效位:

var log2Plus1 = GetLog2Plus1(value);
var bitsToShift = Math.Max(log2Plus1 - 4, 0);
var upper4Bits = value >> bitsToShift;