Reputation: 301
My need is - have some (in-fact pseudo) random number of uint32
, i need it's 4 first bits stating with 1st bit, which in not 0, e.g.
...000100101 => 1001
1000...0001 => 1000
...0001 => 0001
...0000 => 0000
etc I understand i have to use something like this
uint num = 1157 (some random number)
uint high = num >> offset
The problem is - i don't know where the first bit is so i can't use >>
with constant variable. Can some one explain how to find this offset
?
Upvotes: 3
Views: 619
Reputation: 106906
Determining the position of the most significant non-zero bit is the same as computing the logarithm with base 2. There are "bit shift tricks" to do that quickly on a modern 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;
}
This will return a number from 0 to 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 will notice that the logarithm of 0 is undefined. However, I hope the table above demonstrates how that is handled and makes sense for this problem.)
You can then compute the most significant non-zero bits taking into account that you want the 4 least significant bits if the value is less than 8 (where log2 + 1 is < 4):
var log2Plus1 = GetLog2Plus1(value);
var bitsToShift = Math.Max(log2Plus1 - 4, 0);
var upper4Bits = value >> bitsToShift;
Upvotes: 2
Reputation: 477309
You can first calculate the highest significant bit (HSB) and then shift accordingly. You can this like:
int hsb = -4;
for(uint cnum = num; cnum != 0; cnum >>= 1, hsb++);
if(hsb < 0) {
hsb = 0;
}
uint result = num >> hsb;
So we first aim to detect the index of the highest set bit (or that index minus four). We do this by incrementing hsb
and shifting cnum
(a copy of num
) to the right, until there are no set bits anymore in cnum
.
Next we ensure that there is such set bit and that it has at least index four (if not, then nothing is done). The result is the original num
shifted to the right by that hsb
.
If I run this on 0x123
, I get 0x9
in the csharp
interactive shell:
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
is 0001 0010 0011
in binary. So:
0001 0010 0011
1 001
And 1001
is 9
.
Upvotes: 2