I am just stuck with this small logic that i am not getting it right
int is 32 bits so suppose taking 20 in binary would be like
// 00000000000000000000000000010100
.. now if I perform rightshift operation say 4
int a = 20>>4;
// 00000000000000000000000000000001
..so result is 1
Now say I again take 20 and do 5 right shift operation
int b = 20>>5; //00000000000000000000000000000000
..so result is 0
Now if I do 32 right shift ... why I am getting the same number as I assigned.??
int c = 20>>32; //how does this prints 20 again??
System.out.println("right shift 4= "+a+"\n right shift 5= "+b+"right shift 32 = "+c);
So what I was expecting is after 5 shifts ..any number of shifts should have resulted in the result 0.. but on 32 shifts why I am getting back the assigned value?
When you shift an int only the lower 5 bits of the shift are used. When you shift a long only the lowest 6 bits are used.
From the Java Language Specification section 15.19:
If the promoted type of the left-hand operand is int, only the five
lowest-order bits of the right-hand operand are used as the shift
distance. It is as if the right-hand operand were subjected to a
bitwise logical AND operator & (§15.22.1) with the mask value 0x1f
(0b11111). The shift distance actually used is therefore always in the
range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the
six lowest-order bits of the right-hand operand are used as the shift
distance. It is as if the right-hand operand were subjected to a
bitwise logical AND operator & (§15.22.1) with the mask value 0x3f
(0b111111). The shift distance actually used is therefore always in
the range 0 to 63, inclusive.
JLS 15.19. Shift Operators
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive
Related
I'm trying to bitshift right in order to isolate certain bits from a byte so I wanted an unsigned shift, the "new" bits should be zeros by my understanding. However, I've found that >>> has no difference to >> in my tests. -128 >> 4 = -8 as expected, but -128 >>> 4 should be 8 but I still get -8.
byte data = (byte)-128;
System.out.println((byte)(data >>> 4));
System.out.println((byte)(data >> 4));
Thanks for the help.
The unsigned right-shift operator is indeed doing an unsigned right-shift in this code; it's just hidden because of implicit cast from byte to int. Says the Java Language Specification (§15.19):
The operators << (left shift), >> (signed right shift), and >>> (unsigned right shift) are called the shift operators. The left-hand operand of a shift operator is the value to be shifted; the right-hand operand specifies the shift distance. [...] Unary numeric promotion (§5.6.1) is performed on each operand separately.
Unary numeric promotion means (§5.6.1):
[...] if the operand is of compile-time type byte, short, or char, it is promoted to a value of type int by a widening primitive conversion (§5.1.2).
So your code is evaluated as follows:
The byte value -128 which is the left operand of >>> is promoted to the int value -128, which is 0b11111111111111111111111110000000 in binary.
The unsigned right-shift is done on this int value, with the result 268435448 which in binary is 0b00001111111111111111111111111000. Note that the four left-most bits are zero, as you would expect from an unsigned right-shift.
This result is then explicitly casted to (byte), giving the result -8.
Using the REPL:
> byte b = -128;
> int shifted = b >>> 4;
> shifted
268435448
> (byte) shifted
-8
For the behaviour you want, you can use & 0xFF to do an "unsigned" conversion from byte to int:
> ((b & 0xFF) >>> 4)
8
The signed right shift operator '>>' uses the sign bit to fill the trailing positions and the unsigned right shift operator '>>' do not use the sign bit to fill the trailing positions. It always fills the trailing positions by 0s
At specified in JLS8 at §JLS-15.19
If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
I am not clear about this statement in bold . An example is much appreciated.
It's Java exploiting compiler optimisations from the C and C++ worlds. For a 32 bit int, using an bit-shift argument greater than or equal to 31 will set the resulting value to 0 for a positive int. (For a negative argument the behaviour in C and C++ on shifting is implementation defined).
Whereas in C and C++, actually using a value greater than 31 for a 32 bit int is in fact undefined behaviour, the Java bods have actually defined the behaviour specifically and simply perform the shift with an argument modulo 32 (which is what the majority of C and C++ compilers actually do). This method is mentioned explicitly in the JLS snippet you've quoted.
Extracting the lowest five order bits of a number is equivalent to taking that number modulo 32.
I encountered misunderstanding of primitive promotion in the next code snippet.
byte a = 2;
int b = a >> 4L;
What would I expect?
long b = (int)a >> 4L;
long b = a >> 4L;
int b = a >> 4L;
int >> long will promote to the larger data type (long) and it won't compile with resulted int type.
What have I received?
It compiles fine. Why?
The JLS won't "promote to the larger datatype" here, because it does not perform binary numeric promotion for shifting operators. This is covered by the JLS, Section 15.19.
Unary numeric promotion (§5.6.1) is performed on each operand separately. (Binary numeric promotion (§5.6.2) is not performed on the operands.)
Unary numeric promotion promotes the byte a to an int. The literal 4L is not changed, but it only needs to be a integral type anyway.
It is a compile-time error if the type of each of the operands of a shift operator, after unary numeric promotion, is not a primitive integral type.
Then for the shifting, only the least 5 significant bits are used to shift an int.
If the promoted type of the left-hand operand is int, then only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
The result of the operator is an int, not a long, so it can be assigned to an int without a compiler error.
The type of the shift expression is the promoted type of the left-hand operand.
By the JLS:
The type of the shift expression is the promoted type of the left-hand operand.
The right-hand operand of a shift operator doesn't have any effect on the expression's type. Unlike with an operator like +, a bigger type on the right doesn't mean the result could be any bigger or any smaller.
I came across an interesting scenario, When working with bitwise shift operator. If the second operand is negative, how does the bitwise shift operation works? .
i.e a << b , "<<" shifts a bit pattern to the left by b bits in a. But if b is neagtive, shouldn't it be an error at runtime ?
I am able to run the below code successfully but I don't understand how it works?
public static void bitwiseleftShift(char testChar)
{
int val=testChar-'a';
int result= 1<<val;
System.out.println("bit wise shift of 1 with val="+val+" is "+result);
}
Input
bitwiseleftShift('A');// ASCII 65
bitwiseleftShift('0'); // ASCII 48
Results
bit wise shift of 1 with val=-32 is 1
bit wise shift of 1 with val=-49 is 32768
ASCII for 'a' is 97. Can someone help me understand how this works?
But if b is neagtive, shouldn't it be an error at runtime?
Not according to the Java Language Specification, section 15.19:
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
So a shift of -32 actually ends up as a shift of 0, and a shift of -49 actually ends up as a shift of 15 - hence the results you saw.
This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Why is (-1 >>> 32) = -1?
The unsigned right shift operator inserts a 0 in the leftmost. So when I do
System.out.println(Integer.toBinaryString(-1>>>30))
output
11
Hence, it is inserting 0 in the left most bit.
System.out.println(Integer.toBinaryString(-1>>>32))
output
11111111111111111111111111111111
Shouldn't it be 0?
See http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.19
If the promoted type of the left-hand operand is int, only the five lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-hand operand were subjected to a bitwise logical AND operator & (§15.22.1) with the mask value 0x1f (0b11111). The shift distance actually used is therefore always in the range 0 to 31, inclusive.
that is -1 >>> 32 is equivalent to -1 >>> 0 and -1 >>> 33 is equivalent to -1 >>> 1
and, especially confusing, -1 >>> -1 is equivalent to -1 >>> 31