Use masks to evaluate bits of a uint512 - c++

If I met something like this:
uint32_t mask = 8;
uint32_t zero = 0;
uint32_t foo[16];
...
if ((foo[0] & mask) != zero)
...
the condition simply checks the first 8 bits of foo[0], which is a 32-bit unsigned int.
If I have the same value previously stored into foo[16] now into an uint512 variable, how can I get the same condition?
Since foo[0] is the first slot of the vector, it means I previously checked the first 8 bits of the first slot, so can I simply use this?
if (("uint512 variable" & mask) != zero)

First of all,
the condition simply checks the first 8 bits of foo[0], which is a 32-bit
unsigned int.
I think you mean the first 32 bits — foo[0] is the first element which is a 32-bit holder.
Assuming there is uint512, I don't understand what exactly do you want to accomplish, but I think it's one of two things:
Check all uint512 as a single entity using a 512-bit mask like this:
uint512_t mask = 8;
uint512_t zero = 0;
uint512_t foo;
...
if ((foo & mask) != zero)
...
Check an 8-bit slice of the 512-bit variable. In this case you can't simply get it as they array version. This is because depending on the endianness of the target machine, the first 8-bit may be the most significant or the least significant 8-bits.
If you want to check the most significant bits:
uint32_t mask = 8;
uint32_t zero = 0;
uint512_t foo;
...
if ((uint32_t)(foo >> 480) & mask) != zero)
...
If you want to check the least significant bits:
uint32_t mask = 8;
uint32_t zero = 0;
uint512_t foo;
...
if (((uint32_t)foo & mask) != zero)
...

Related

Do I have to set most significant bits to zero if I shift right?

Let's say I have a 64-bit number and some bits that are set that hold a value, let's say three bits. I have a mask to get that value. To get the value of those three bits I bitwise 'AND' the number with the mask. This sets all other bits to zero. I then need to shift right towards the least significant bits so the least significant bit of the three-bit number is in the position of the least significant bit of the 64 bit number. After I shift right, do I need to mask again to ensure only all the bits to the left of those three bits are zero?
You can do shift first then the mask and accomplish what you want:
int value = 0xdeadbeef;
value >>= 15;
value &= 0x7;
In prior versions of the C++ standard, right-shifts of negative values were implementation-defined because signed integers could be one's-complement, two's-complement or sign+magnitude. So the behavior of right shift of a negative was implementation defined.
But all implementations of (modern) C++ are for CPUs using two's-complement and a lot of existing code relies on that implementation detail. In C++ 2020 this was finally acknowledged and signed integers are now defined as two's-complement.
The way shift right works depends on the type of the argument:
int value = -1;
value >>= 10;
Assuming two's-complement, which is now required, this will use an arithmetic shift and preserves the sign bit. So after the shift the value will still be -1 and have all bits set. If you mask before the shift then after the shift you get more bits then you bargained for.
unsigned int value = 0xFFFFFFFF;
value >>= 10;
This will use a logical shift and add zeroes to the left. So if you mask before the shift then you still get the right bits after the shift.
But why mask before the shift? If you mask after the shift then you always get the right bits regardless of the type.
Do I have to set most significant bits to zero if I shift right?
After I shift right, do I need to mask again to ensure only all the bits to the left of those three bits are zero?
Yes, if the result of the mask was a signed type, a mask needed to cope with the sign bit shifted.
No if the result of the mask was a unsigned type.
uint64_t mask = ...;
uint64_t masked_value = mask & value;
uint64_t final = masked_value >> shift_amount;
If code did:
int64_t mask = 7 << shift_amount;
int64_t masked_value = mask & value;
int64_t almost_final = masked_value >> shift_amount;
int final = (int) (masked_value & 7);
A smart compiler may emit efficient as as the unsigned approach above.

Use bit manipulation to convert a bit from each byte in an 8-byte number to a single byte

I have a 64-bit unsigned integer. I want to check the 6th bit of each byte and return a single byte representing those 6th bits.
The obvious, "brute force" solution is:
inline const unsigned char Get6thBits(unsigned long long num) {
unsigned char byte(0);
for (int i = 7; i >= 0; --i) {
byte <<= 1;
byte |= bool((0x20 << 8 * i) & num);
}
return byte;
}
I could unroll the loop into a bunch of concatenated | statements to avoid the int allocation, but that's still pretty ugly.
Is there a faster, more clever way to do it? Maybe use a bitmask to get the 6th bits, 0x2020202020202020 and then somehow convert that to a byte?
If _pext_u64 is a possibility (this will work on Haswell and newer, it's very slow on Ryzen though), you could write this:
int extracted = _pext_u64(num, 0x2020202020202020);
This is a really literal way to implement it. pext takes a value (first argument) and a mask (second argument), at every position that the mask has a set bit it takes the corresponding bit from the value, and all bits are concatenated.
_mm_movemask_epi8 is more widely usable, you could use it like this:
__m128i n = _mm_set_epi64x(0, num);
int extracted = _mm_movemask_epi8(_mm_slli_epi64(n, 2));
pmovmskb takes the high bit of every byte in its input vector and concatenates them. The bits we want are not the high bit of every byte, so I move them up two positions with psllq (of course you could shift num directly). The _mm_set_epi64x is just some way to get num into a vector.
Don't forget to #include <intrin.h>, and none of this was tested.
Codegen seems reasonable enough
A weirder option is gathering the bits with a multiplication: (only slightly tested)
int extracted = (num & 0x2020202020202020) * 0x08102040810204 >> 56;
The idea here is that num & 0x2020202020202020 only has very few bits set, so we can arrange a product that never carries into bits that we need (or indeed at all). The multiplier is constructed to do this:
a0000000b0000000c0000000d0000000e0000000f0000000g0000000h0000000 +
0b0000000c0000000d0000000e0000000f0000000g0000000h00000000000000 +
00c0000000d0000000e0000000f0000000g0000000h000000000000000000000 etc..
Then the top byte will have all the bits "compacted" together. The lower bytes actually have something like that too, but they're missing bits that would have to come from "higher" (bits can only move to the left in a multiplication).

Change the width of a signed integer to a nonstandard width

For a networking application I need a signed, 2's complement integer. With a custom width. Specified at run time. Assuming the value of the integer falls in the width.
The problem I have is the parity bit. Is there any way of avoid having to manually set the parity bit? Say I have an integer with a width of 11 bits, i'll store it in an array of 2 chars like this:
int myIntWidth = 11;
int32_t myInt= 5;
unsigned char charArray[2] = memcpy(charArray, &myInt, (myIntWidth + 7)/8);
It doesn't work like that. It can't work, because you are copying two bytes from the start of myInt but you don't know where the bytes that you are interested in are stored. You also need to know in which order you are supposed to store the bytes. Depending on that, use one of these two codes:
unsigned char charArray [2];
charArray [0] = myInt & 0xff; // Lowest 8 bits
charArray [1] = (myInt >> 8) & 0x07; // Next 3 bits
or
unsigned char charArray [2];
charArray [1] = myInt & 0xff; // Lowest 8 bits
charArray [0] = (myInt >> 8) & 0x07; // Next 3 bits
With the help of a lot of the posts above, I've come up with this solution:
inline void reduceSignedIntWidth(int32_t& destInt, int width)
{
//create a value mask, with 1's at the masked part
uint32_t l_mask = (0x01u << width) - 1;
destInt &= l_mask;
}
It will return the reduced int, with zeros as padding.

Bits shifted by bit shifting operators(<<, >>) in C, C++

can we access the bits shifted by bit shifting operators(<<, >>) in C, C++?
For example:
23>>1
can we access the last bit shifted(1 in this case)?
No, the shift operators only give the value after shifting. You'll need to do other bitwise operations to extract the bits that are shifted out of the value; for example:
unsigned all_lost = value & ((1 << shift)-1); // all bits to be removed by shift
unsigned last_lost = (value >> (shift-1)) & 1; // last bit to be removed by shift
unsigned remaining = value >> shift; // lose those bits
By using 23>>1, the bit 0x01 is purged - you have no way of retrieving it after the bit shift.
That said, nothing's stopping you from checking for the bit before shifting:
int value = 23;
bool bit1 = value & 0x01;
int shifted = value >> 1;
You can access the bits before shifting, e.g.
value = 23; // start with some value
lsbits = value & 1; // extract the LSB
value >>= 1; // shift
It worth signal that on MSVC compiler an intrinsic function exists: _bittest
that speeds up the operation.

How to set specific bits?

Let's say I've got a uint16_t variable where I must set specific bits.
Example:
uint16_t field = 0;
That would mean the bits are all zero: 0000 0000 0000 0000
Now I get some values that I need to set at specific positions.
val1=1; val2=2, val3=0, val4=4, val5=0;
The structure how to set the bits is the following
0|000| 0000| 0000 000|0
val1 should be set at the first bit on the left. so its only one or zero.
val2 should be set at the next three bits. val3 on the next four bits. val4 on the next seven bits and val5 one the last bit.
The result would be this:
1010 0000 0000 1000
I only found out how to the one specific bit but not 'groups'. (shift or bitset)
Does anyone have an idea how to solve this issue?
There are (at least) two basic approaches. One would be to create a struct with some bitfields:
struct bits {
unsigned a : 1;
unsigned b : 7;
unsigned c : 4;
unsigned d : 3;
unsigned e : 1;
};
bits b;
b.a = val1;
b.b = val2;
b.c = val3;
b.d = val4;
b.e = val5;
To get the 16-bit value, you could (for one example) create a union of that struct with a uint16_t. Just one minor problem: the standard doesn't guarantee what order the bit fields will end up in when you look at the 16-bit value. Just for example, you might need to reverse the order I've given above to get the order from most to least significant bits that you really want (but changing compilers might muck things up again).
The other obvious possibility would be to use shifting and masking to put the pieces together into a number:
int16_t result = val1 | (val2 << 1) | (val3 << 8) | (val4 << 12) | (val5 << 15);
For the moment, I've assumed each of the inputs starts out in the correct range (i.e., has a value that can be represented in the chosen number of bits). If there's a possibility that could be wrong, you'd want to mask it to the correct number of bits first. The usual way to do that is something like:
uint16_t result = input & ((1 << num_bits) - 1);
In case you're curious about the math there, it works like this. Lets's assume we want to ensure an input fits in 4 bits. Shifting 1 left 4 bits produces 00010000 (in binary). Subtracting one from that then clears the one bit that's set, and sets all the less significant bits than that, giving 00001111 for our example. That gives us the first least significant bits set. When we do a bit-wise AND between that and the input, any higher bits that were set in the input are cleared in the result.
One of the solutions would be to set a K-bit value starting at the N-th bit of field as:
uint16_t value_mask = ((1<<K)-1) << N; // for K=4 and N=3 will be 00..01111000
field = field & ~value_mask; // zeroing according bits inside the field
field = field | ((value << N) & value_mask); // AND with value_mask is for extra safety
Or, if you can use struct instead of uint16_t, you can use Bit fields and let the compiler to perform all these actions for you.
finalvle = 0;
finalvle = (val1&0x01)<<15;
finalvle += (val2&0x07)<<12;
finalvle += (val3&0x0f)<<8
finalvle += (val4&0xfe)<<1;
finalvle += (val5&0x01);
You can use the bitwise or and shift operators to achieve this.
Use shift << to 'move bytes to the left':
int i = 1; // ...0001
int j = i << 3 // ...1000
You can then use bitwise or | to put it at the right place, (assuming you have all zeros at the bits you are trying to overwrite).
int k = 0; // ...0000
k |= i // ...0001
k |= j // ...1001
Edit: Note that #Inspired's answer also explains with zeroing out a certain area of bits. It overall explains how you would go about implementing it properly.
try this code:
uint16_t shift(uint16_t num, int shift)
{
return num | (int)pow (2, shift);
}
where shift is position of bit that you wanna set