Why is there a >>> op

Dec 12, 2019 at 2:37am
What is the difference between >> and >>>? I’v heard they are the 'right shift' op and the 'shift right zero fill' op, but I don’t get it. Shouldn’t the >> already be zero filled?!? I’m a little scared now..

1
2
3
4
5
6
7
8
 #include <iostream>
 #include <bitset>

 int main(){
   unsigned short i = 32; // 00000000 00100000
   std::cout << std::bitset::bitset( (i >> 4) ); // ???????? ??????10 what’s happening??
   std::cout << std::bitset::bitset( (i >> 4) ); // 00000000 00000010 It’s ok... I think. This is what’s, happening right?
 }


Edit: 🤦‍♂️ I just tried to use code tags in the title.
Last edited on Dec 12, 2019 at 2:44am
Dec 12, 2019 at 2:49am
There is no >>> in C++. It's from Java.
With the >> shift operator in C++, it is up to the implementation whether it shifts in a zero or whether it repeats the sign bit (which may of course be 1).
Last edited on Dec 12, 2019 at 2:50am
Dec 12, 2019 at 3:06am
Oh no... this is literally making me wonky ahh!!! I thought they just always zero filled!! Oh well. Thanks! :)
Dec 12, 2019 at 3:23am
There are two kinds of right-shifts in a CPU: logical and arithmetic. A logical shift always shifts in a zero bit. An arithmetic shift always shift in a copy of the sign bit. Which type of shift >> represents is implementation dependent. Java added the >>> operator to specifically represent a logical shift, so presumably >> is always arithmetic in Java.
Dec 12, 2019 at 9:19am
>> will do logical shifts when used on unsigned integers. This is the same as what Java's >>> operator does.

>> on signed integers is currently implementation defined for negative values. In C++20 it will be guaranteed to do arithmetic shifts which is the same as Java's >> operator does.

You can test the difference between logical (unsigned) and arithmetic (signed) shifts on this page:
https://onlinetoolz.net/bitshift#base=10&value=32&bits=16&steps=4&dir=r&type=log&allsteps=0
Last edited on Dec 12, 2019 at 9:27am
Dec 12, 2019 at 1:56pm
or, bluntly, java needed >>> because java forgot to allow unsigned int types. This operator is used in some languages to limit the size of ints as well, where the type isn't correctly defended (weak typing) against changing behind the scenes, eg if you wanted to shift a 32 bit int but the result is too big so its hidden promoted to 64 bits instead of giving the correct 32 bit truncated result. C++ needs none of this because it is strongly typed and has unsigned types.
Dec 12, 2019 at 6:00pm
Oh oops didn’t notice people were still responding.
@everyone good to know.. kinda relieved because I’m using unsigned.
Dec 12, 2019 at 6:23pm
An arithmetic shift always shift in a copy of the sign bit.
This is incorrect. Arithmetic shift is equivalent to integer division by a power of 2, regardless of how the CPU represents signed integers. For example, in a CPU that represents integers like this:

-16 = 00000
...
-1 = 01111
0 = 10000
1 = 10001
...
15 = 11111

arithmetic shift and bitwise shift would be quite different.
Dec 12, 2019 at 6:38pm
helios wrote:
Arithmetic shift is equivalent to integer division by a power of 2

This is incorrect. :-)
https://en.wikipedia.org/wiki/Arithmetic_shift#Non-equivalence_of_arithmetic_right_shift_and_division

1
2
3
4
5
6
7
#include <iostream>
int main() {
    int a = -1;
    std::cout << (a >> 1) << '\n';   // prints -1
    std::cout << (a / 2)  << '\n';   // prints  0
    return 0;
}

Still, point taken. But the only common place I know of that uses the "biased" representation is in floating point exponents (for some reason).


jonin wrote:
or, bluntly, java needed >>> because java forgot to allow unsigned int types.

Well, that's interesting!

We should make it very clear that in C++ (and C) right-shifts should probably only be used with unsigned integers (or possibly positive values of signed integers).
Last edited on Dec 12, 2019 at 6:49pm
Dec 12, 2019 at 7:13pm
This is exactly why I never do bitwise operations on signed values. :-)
Dec 13, 2019 at 3:56am
We should make it very clear that in C++ (and C) right-shifts should probably only be used with unsigned integers (or possibly positive values of signed integers).

It depends on what its for. If its something like a CRC32 algorithm, you just say (unsigned int)(variable) >> n; and its fine because you are just making a binary soup of the bit anyway, the result isn't of much numerical use, the actual value has no meaning apart from 'does it match a previous result of same data' or 'can I repair damaged bit with it' type questions.

If its something where you were dividing by a power of 2, it matters a whole lot.
Topic archived. No new replies allowed.