Reputation: 1087
I have next code:
std::cout << (-10 >> 1) << std::endl;
std::cout << (-9 >> 1) << std::endl;
std::cout << (-8 >> 1) << std::endl;
std::cout << (-7 >> 1) << std::endl;
std::cout << (-6 >> 1) << std::endl;
std::cout << (-5 >> 1) << std::endl;
std::cout << (-4 >> 1) << std::endl;
std::cout << (-3 >> 1) << std::endl;
std::cout << (-2 >> 1) << std::endl;
std::cout << (-1 >> 1) << std::endl;
The result is:
-5
-5
-4
-4
-3
-3
-2
-2
-1
-1
But why?
-1
is 1111 1111
(for 1 byte), -1 >>
1 must be : 1011 1111
and it is not -1
or 0
! (sign-bit is not shifted, I know)
Can someone explain to me how this works?
Upvotes: 16
Views: 673
Reputation: 27474
In general, right-shifts are defined as being implemented as either "arithmetic" or "logical" The difference is that with a logical right shift, the left-most bit is always set to zero. With an arithmetic right shift, the left-most bit is a copy of the previous value.
For example, let's pretend the value is just 8 bits to make things easier to keep track of. Then:
Logical:
0111 1111 >> 1 = 0011 1111
1111 1111 >> 1 = 0111 1111
1111 1110 >> 1 = 0111 1111
Arithmetic:
0111 1111 >> 1 = 0011 1111
1111 1111 >> 1 = 1111 1111
1111 1110 >> 1 = 1111 1111
An arithmetic right-shift is equivalent to dividing by 2 and rounding toward negative infinity.
In C++, whether the right-shift operator is logical or arithmetic is implementation-specific. i.e. each compiler writer may decide for himself, probably based on what is easier to do giving the architecture of the computer he's working on.
Your statement that the sign bit is not shifted is incorrect. The sign bit is shifted just like all the other bits. The only question is what replaces it.
Java has two different right-shift operators: >> is arithmetic and >>> is logical.
Upvotes: 3
Reputation: 93476
-1 >> 1 must be : 1011 1111
If that were true, -10 >> 1 would be 10111011 == -69 in two's complement. Not a very useful result!
Although the language behaviour is undefined (so the result, useful or otherwise cannot be relied upon), the common behaviour (and that exhibited in this case) is to perform "sign-extension".
It is not true that the "sign-bit is not shifted", it is shifted, and the vacated bit is filled with a value equal to the sign bit. This behavour both preserves the sign and provides the 'expected' divide-by-two operation that you have observed for all values except -1. For negative values -1 is the 'terminal value' of a right shift, as zero is for positive numbers. That is to say right shift of a negative number tends to -1, and a positive number tends to zero.
Upvotes: 3
Reputation: 189686
Right-shifting a negative number is implementation-defined.
Implementations which shift in a sign-extended bit to the leftmost bit, work as you reported.
As for why it is done this way, it's because right-shifting can be used to divide by a power of 2 with round-towards-negative-infinity (e.g. like floor()
) rounding behavior:
(-8 >> 2) == -2
(-9 >> 2) == -3
(-10 >> 2) == -3
(-11 >> 2) == -3
(-12 >> 2) == -3
Upvotes: 17
Reputation: 76755
Standard 5.8/3 (Shift operators) :
The value of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type or if E1 has a signed type and a nonnegative value, the value of the result is the integral part of the quotient of E1 divided by the quantity 2 raised to the power E2. If E1 has a signed type and a negative value, the resulting value is implementation-defined.
So to the question "why ?", the standard answer is : why not.
Upvotes: 24