我的需求是 - 有一些(实际上伪)随机数uint32
,我需要它的4个第一位用第1位表示,而不是0,例如。
... 000100101 => 1001
1000 ... 0001 => 1000
... 0001 => 0001
... 0000 => 0000
等 我明白我必须使用这样的东西
uint num = 1157 (some random number)
uint high = num >> offset
问题是 - 我不知道第一位在哪里所以我不能将>>
用于常量变量。有人可以解释如何找到这个offset
吗?
答案 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
并将cnum
(num
的副本)向右移动来实现此目的,直到cnum
中不再存在设置位。
接下来,我们确保有这样的设置位,并且它至少具有索引4(如果没有,则不执行任何操作)。结果是原始num
被hsb
向右移动。
如果我在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
而1001
是9
。
答案 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;