【问题标题】:C# getting upper 4 bits of uint32 starting with first significant bitC# 从第一个有效位开始获取 uint32 的高 4 位
【发布时间】:2017-05-11 09:25:12
【问题描述】:

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

...000100101 => 1001

1000...0001 => 1000

...0001 => 0001

...0000 => 0000

等 我知道我必须使用这样的东西

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

问题是 - 我不知道第一位在哪里,所以我不能将>> 与常量变量一起使用。谁能解释一下如何找到这个offset

【问题讨论】:

  • 是否保证有这样的位。在00000010 的情况下会发生什么?

标签: c# bit-manipulation uint32


【解决方案1】:

确定最重要的非零位的位置与计算以 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 的数字:

价值 |日志2 + 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

(数学挑剔者会注意到 0 的对数是未定义的。但是,我希望上表演示了如何处理它并对这个问题有意义。)

如果值小于 8(其中 log2 + 1 为

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

【讨论】:

    【解决方案2】:

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

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

    所以我们首先要检测最高设置位的索引(或该索引减四)。我们通过递增hsb 并将cnumnum 的副本)向右移动,直到cnum 中不再有设置位。

    接下来,我们确保存在这样的设置位,并且它至少具有索引 4(如果没有,则什么也不做)。结果是原来的num 向右移动了hsb

    如果我在0x123 上运行它,我会在csharp 交互式shell 中得到0x9

    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

    【讨论】:

      猜你喜欢
      • 2020-06-09
      • 1970-01-01
      • 2020-09-07
      • 1970-01-01
      • 1970-01-01
      • 2019-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多