Java's unsigned bitshift right (>>>) is signed shifting - java

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

Related

Java byte to short convert randomly attached 0xff problem

I am trying to cast from byte to short, but the value is randomly attached to 0xff. Is there a way to handle it normally?
short[] shortArray = new short[size];
for (int index = 0; index < size; index++)
shortArray[index] = (short) byteArray[index];
The negative numbers always must have 1 in leftmost bit.
If byte array has negative numbers, their representation in short format requires left byte to be 0xff to keep the same negative value.
For example:
the decimal byte value -2 is binary 0b1111_1110 or hexadecimal 0xfe
the decimal short value -2 is binary 0b1111_1111_1111_1110 or hexadecimal 0xfffe
Looks like you want to do an unsigned conversion (e.g. got results in range [0..255]).
byte is a signed type in Java, so converting negative byte values to short will produce negative numbers (and in two's complement system you'll see 0xff prefix).
Bit representation, however, is same for signed and unsigned bytes, for example (byte) 0xFF means 255 as unsigned, but is -1 if treated as signed one.
Unsigned conversion can be done by implicit promotion to int, picking 8 low bits using AND and downcasting result to short:
shortArray[index] = (short) (byteArray[index] & 0xFF);

Logical right shift operator in java

I am beginner to java... I have tried very much but could not find the way the following line
System.out.println (-1>>>1);
gives 2147483647 ?
Can anyone help me ?
This is because the binary representation of -1 is 11111111111111111111111111111111. When you perform an unsigned right bit-shift operation (>>>) on it it moves all of the bits right by the argument (1 in this case) and fills in empty spaces on the left with zeros so you get 01111111111111111111111111111111 which is the binary representation of Integer.MAX_VALUE = 2147483647 (not sure where you got 2147483648 from).
>>> is the bitwise right-shift operator, with 0 sign extension - in other words, all bits "incoming" from the left are filled with 0s.
-1 is represented by 32 bits which are all 1. When you shift that right by 1 bit with 0 sign extension, you end up with a value which has the 31 bottom bits still 1, but 0 for the top bit (the sign bit), so you end up with Integer.MAX_VALUE - which is 2147483647, not 2147483648 as your post states.
Or in JLS terms, from section 15.19:
The value of n >>> s is n right-shifted s bit positions with zero-extension, where:
If n is positive, then the result is the same as that of n >> s.
If n is negative and the type of the left-hand operand is int, then the result is equal to that of the expression (n >> s) + (2 << ~s).
If n is negative and the type of the left-hand operand is long, then the result is equal to that of the expression (n >> s) + (2L << ~s).
This definition ends up being a bit of a pain to work with - it's easier to just work with the "0 sign extension right-shift" explanation, IMO.

Unsigned right shift in Java

Simple question: why if I apply unsigned right shift in Java to byte variable (and short as well) it threats it as int:
byte x = -1;
System.out.println(x >> 2);
System.out.println(x >>> 1);
System.out.println(Integer.MAX_VALUE);
Console output:
-1
2147483647
2147483647
One can only use the shift operators on ints and longs in Java (just like all other numeric operators), thus the byte is automatically cast to an int before shifting it. This also happens with the arithmetical right shift, but -1 >> 2 is -1 no matter what type -1 is, because the binary representation 111...111 shifted right arithmetically is still 111...111, while shifted logically it becomes 011...111, i.e. the maximum value of the shifted type.
PS: An arithmetic shift is a signed shift, and a logical shift is an unsigned shift.

signed byte type and bitwise operators in Java?

quoting from oracle website "byte: The byte data type is an 8-bit signed two's complement integer. It has a minimum value of -128 and a maximum value of 127 (inclusive)".
here, the first two lines are valid but the last is not
byte b = -128;
byte b1 = 127;
byte b2 = b>>>b1;//illegal
Q1) what is meant exactly by 8-bit signed? 128 in binary format would be 1000 0000 and -128 would need an extra bit for the negative sign, where it would fit if all the 8 bits are occupied.
Q2) for int, there is a unsigned right shift operator, but that seems illegal with bytes, why is it so. can overflow not be prevented in case of bytes. In case of int, it works
Thanks for your help
Just what it sounds like: There are 8 bits, holding 2^8 = 256 possible values. It's signed, so the range is frmo -128 through 127 (256 values). The most significant bit has a value of -128.
In Java, binary numeric promotion occurs with operations such as b >>> b1. Both types are promoted to int, and the result is an int. However, you can explicitly cast the result back to byte.
Here's the cast:
byte b2 = (byte) (b >>> b1);
The JLS, Section 5.6.2, talks about binary numeric promotion:
Widening primitive conversion (§5.1.2) is applied to convert either or
both operands as specified by the following rules:
If either operand is of type double, the other is converted to double.
Otherwise, if either operand is of type float, the other is converted
to float.
Otherwise, if either operand is of type long, the other is converted
to long.
Otherwise, both operands are converted to type int.
(emphasis mine)

Bit wise shift operator with shift by negative number

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.

Categories

Resources