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

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.

Related

C/C++ Bitwise Operations not resulting in expected output?

I'm currently working on bitwise operations but I am confused right now... Here's the scoop and why
I have a byte 0xCD in bits this is 1100 1101
I am shifting the bits left 7, then I'm saying & 0xFF since 0xFF in bits is 1111 1111
unsigned int bit = (0xCD << 7) & 0xFF<<7;
Now I would make the assumption that both 0xCD and 0xFF would get shifted to the left 7 times and the remaining bit would be 1&1 = 1 but I'm not getting that for output also I would also make the assumption that shifting 6 would give me bits 0&1 = 0 but I'm getting again a number above 1 like 205 0.o Is there something incorrect about the way I am trying to process bit shifting in my head? If so what is it that I am doing wrong?
Code Below:
unsigned char byte_now = 0xCD;
printf("Bits for byte_now: 0x%02x: ", byte_now);
/*
* We want to get the first bit in a byte.
* To do this we will shift the bits over 7 places for the last bit
* we will compare it to 0xFF since it's (1111 1111) if bit&1 then the bit is one
*/
unsigned int bit_flag = 0;
int bit_pos = 7;
bit_flag = (byte_now << bit_pos) & 0xFF;
printf("%d", bit_flag);
Is there something incorrect about the way I am trying to process bit shifting in my head?
There seems to be.
If so what is it that I am doing wrong?
That's unclear, so I offer a reasonably full explanation.
In the first place, it is important to understand that C does not not perform any arithmetic directly on integers smaller than int. Consider, then, your expression byte_now << bit_pos. "The usual arithmetic promotions" are performed on the operands, resulting in the left operand being converted to the int value 0xCD. The result has the same pattern of least-significant value bits as bit_flag, but also a bunch of leading zero bits.
Left shifting the result by 7 bits produces the bit pattern 110 0110 1000 0000, equivalent to 0x6680. You then perform a bitwise and operation on the result, masking off all but the least-significant 8 bits, thus yielding 0x80. What happens when you assign that to bit_flag depends on the type of that variable, but if it is an integer type that is either unsigned or has more than 7 value bits then the assignment is well-defined and value-preserving. Note that it is bit 7 that is nonzero, not bit 0.
The type of bit_flag is more important when you pass it to printf(). You've paired it with a %d field descriptor, which is correct if bit_flag has type int and incorrect otherwise. If bit_flag does have type int, then I would expect the program to print 128.

How can you get the j first most significant bits of an integer in C++?

I know that to get the first j least significant bits of an integer you can do the following:
int res = (myInteger & ((1<<j)-1))
Can you do something similar for the most significant bits?
Simply right shift: (Warning, fails when you want 0 bits, but yours fails for all bits)
unsigned dropbits = CHAR_BIT*sizeof(int)-j;
//if you want the high bits moved to low bit position, use this:
ullong res = (ullong)myInteger >> dropbits;
//if you want the high bits in the origonal position, use this:
ullong res = (ullong)myInteger >> dropbits << dropbits;
Important! The cast must be the unsigned version of your type.
It's also good to note that your code for the lowest j bits fails when you ask it for all (32?) bits. As such, it can be easier to doubleshift:
unsigned dropbits = CHAR_BIT*sizeof(int)-j;
ullong res = (ullong)myInteger << dropbits >> dropbits;
See it working here: http://coliru.stacked-crooked.com/a/64eb843b3b255278 and here: http://coliru.stacked-crooked.com/a/29bc40188d852dd3
To get the j highest bits of an integer (or rather an unsigned integer, because bitwise operations in signed integers are a recipe for pain):
unsigned res = myUnsignedInteger & ~(~0u >> j);
~0u consists of only set bits. Shifting that j bits to the right gives us j zero-bits on the left side followed by one-bits, and inverting that gives us j one-bits on the left followed by zeroes, which is the mask we need to isolate the j highest bits of another integer.
Note: This is under the assumption that you want the isolated bits to remain in the same place, which is to say
(0xdeadbeef & ~(~0u >> 12)) == 0xdea00000

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.

why is this method for computing sign of an integer architecture specific

From this link here to compute the sign of an integer
int v; // we want to find the sign of v
int sign; // the result goes here
sign = v >> (sizeof(int) * CHAR_BIT - 1);
// CHAR_BIT is the number of bits per byte (normally 8)
If I understand this correctly, if sizeof(int) = 4 bytes => 32 bits
MSB or 32nd bit is reserved for the sign. So, we right shift by (sizeof(int) * CHAR_BIT - 1) and all the bits fall off from the right side, leaving only the previous MSB at index 0. If MSB is 1 => v is negative otherwise it is positive.
Is my understanding correct ?
If so, then can someone please explain me what author meant here by this approach being architecture specific:
This trick works because when signed integers are shifted right, the
value of the far left bit is copied to the other bits. The far left
bit is 1 when the value is negative and 0 otherwise; all 1 bits gives
-1. Unfortunately, this behavior is architecture-specific.
How will this be any different for a 32 bit or 64 bit architecture ?
I believe that the "architecture dependent" is based on what sorts of shift operations the processor supports. x86 (16, 32 and 64-bit modes) support an "arithmetic shift" and "logical shift". The arithmetic variant copies the top bit of the shifted value down along as it shifts, the logical shift does not, it fills with zeros.
However, to avoid the compiler having to generate code along the lines of:
int temp = (1 << 31) & v;
sign = v;
for(i = 0; i < 31; i++)
sign = temp | (sign >> 1);
to avoid the problem of an architecture that ONLY has the "logical" shift.
Most architectures have both variations, but there are processors that don't. (Sorry, I can't find a reference that shows which processors has and hasn't got two variants of shift).
There may also be issues with 64-bit machines that can't distinguish between 64 and 32 bit shifts, and thus shift in the upper 32 bits from the number, rather than the lesser sign bit. Not sure if such processors exist or not.
The other part is of course to determine if the sign for -0 in a ones complement is actually a "0" or "-1" result in terms of sign. This really depends on what you are trying to do.
It's "architecture-dependent" because in C++ the effect of a right shift of a negative value is implementation defined (in C it produces undefined behavior). That, in turn, means that you cannot rely on the result unless you've read and understood your compiler's documentation of what it does. Personally, I'd trust the compiler to generate appropriate code for v < 0 ? -1 : 0.

Shift left/right adding zeroes/ones and dropping first bits

I've got to program a function that receives
a binary number like 10001, and
a decimal number that indicates how many shifts I should perform.
The problem is that if I use the C++ operator <<, the zeroes are pushed from behind but the first numbers aren't dropped... For example
shifLeftAddingZeroes(10001,1)
returns 100010 instead of 00010 that is what I want.
I hope I've made myself clear =P
I assume you are storing that information in int. Take into consideration, that this number actually has more leading zeroes than what you see, ergo your number is most likely 16 bits, meaning 00000000 00000001 . Maybe try AND-ing it with number having as many 1 as the number you want to have after shifting? (Assuming you want to stick to bitwise operations).
What you want is to bit shift and then limit the number of output bits which can be active (hold a value of 1). One way to do this is to create a mask for the number of bits you want, then AND the bitshifted value with that mask. Below is a code sample for doing that, just replace int_type with the type of value your using -- or make it a template type.
int_type shiftLeftLimitingBitSize(int_type value, int numshift, int_type numbits=some_default) {
int_type mask = 0;
for (unsigned int bit=0; bit < numbits; bit++) {
mask += 1 << bit;
}
return (value << numshift) & mask;
}
Your output for 10001,1 would now be shiftLeftLimitingBitSize(0b10001, 1, 5) == 0b00010.
Realize that unless your numbits is exactly the length of your integer type, you will always have excess 0 bits on the 'front' of your number.