0

I am trying to extract the lower 25 bits of uint64_t to uint32_t. This solution shows how to extract lower 16 bits from uint32_t, but I am not able to figure out for uint64_t. Any help would be appreciated.

viz12
  • 675
  • 1
  • 11
  • 20
  • 1
    `uint32_t foo = someInt64 & ((1 << 25) - 1);` or `uint32_t foo = someInt64 & 0x1ffffff;` This answer explains that: https://stackoverflow.com/a/39258841/920069 – Retired Ninja Apr 21 '18 at 19:48
  • 1
    Assuming `x` is a uint64_t, you can do `x = x ^ (x >> 25 << 25);` as a quick way to get it. Or you can do `x = x & ((uint64_t{1} << 25) - 1); – Eljay Apr 21 '18 at 19:52
  • @RetiredNinja That works !! Thanks !! – viz12 Apr 21 '18 at 19:55

2 Answers2

3

See How do you set, clear, and toggle a single bit? for bit operations.

To answer your question:

uint64_t lower25Bits = inputValue & (uint64_t)0x1FFFFFF;
Quimby
  • 17,735
  • 4
  • 35
  • 55
3

Just mask with a mask that leaves just the bits you care about.

uint32_t out = input & ((1UL<<26)-1);

The idea here is: 1UL<<26 provides an (unsigned long, which is guaranteed to be at least 32-bit wide) integer with just the 26th bit set, i.e.

00000100000000000000000000000000

the -1 makes it become a value with all the bits below it set, i.e.:

00000011111111111111111111111111

the AND "lets through" only the bits that in the mask correspond to zero.


Another way is to throw away those bits with a double shift:

uint32_t out = (((uint32_t)input)<<7)>>7;

The cast to uint32_t makes sure we are dealing with a 32-bit wide unsigned integer; the unsigned part is important to get well-defined results with shifts (and bitwise operations in general), the 32 bit-wide part because we need a type with known size for this trick to work.

Let's say that (uint32_t)input is

11111111111111111111111111111111

we left shift it by 32-25=7; this throws away the top 7 bits

11111111111111111111111110000000

and we right-shift it back in place:

00000001111111111111111111111111

and there we go, we got just the bottom 25 bits.

Notice that the first uint32_t cast wouldn't be strictly necessary because you already have a known-size unsigned value; you could just do (input<<39)>>39, but (1) I prefer to be sure - what if tomorrow input becomes a type with another size/signedness? and (2) in general current CPUs are more efficient working with 32 bit integers than 64 bit integers.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299