6 AnswersNew Answer
in the Java Language Specification book for Java SE 16 it is written "... 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). ..." so it works properly only on int (short and byte are promoted to int) and long https://docs.oracle.com/javase/specs/jls/se16/html/jls-15.html#jls-15.19
I'm guessing it has something to do with the number of bits supported by the `byte` type. From what I read https://cs-fundamentals.com/java-programming/java-operators-precedence-and-associativity that >>> was meant for "unsigned or zero fill right shift". But IIRC there is no unsigned `byte` in java. Because the number of usable bits for signed and unsigned type were different, and the fact that `byte` only is 1 byte in size, shifting the bits results in unexpected output (yields -1 instead of 1). If you use %d for output, you will see -1 (in 8 bits binary => 11111111). If `int` was used rather than `byte`, you will get 1 as result.
I can't agree. A bit operator operates on bits and not on the type of data used. In Java, integer types are prefixed and machine independent. byte 8 bit, short 16 bit, int 32 bit, long 64 bit and they are all signed (two's complement). From the definition >>> must not propagate the sign bit but insert zeros. So a byte z = -128 (equivalent to 0b1000_000) shifted to the right by 7 bits with >>> must produce 1 while with >> it must produce 255 (0b1111_1111) that is, it propagates the sign. why isn't it like that? looking and studying I came to the conclusion that the problem is related to the fact that the operator >>> returns and work with int so int work, long work, byte and short require more attention
No problem at all It's just what I think, I never said it must be right 👌
Ciro Pellegrino, As you quite rightly state it only works properly on int and long due to promotion. All integer values (byte, short, int, and long) are signed in Java. When performing shift operations on byte and short values they are promoted to int values first. Since a signed integer value has its most significant bit (msb) set for negative values when it is promoted to an int the value is sign extended with 1's filling the leftmost bits. Conversely a positive number is sign extended by filling the leftmost bits with 0's. Thus a byte value of 0x80 is -128 or 1000 0000. When this is sign extended into an integer for shifting it remains as -128 but becomes 0xFFFFFF80 which is: 1111 1111 1111 1111 1111 1111 1000 0000 in binary. Consequently it matters not if you use >> or >>> on the value if the reusult is cast back to a byte. This also applies to short values as well. One way around this is to use the static methods Byte.toUnsignedInt(byte x) and Short.toUnsignedInt(short x) to create an int, perform the shift operation, then cast the result back as required. The methods Integer.byteValue() and Integer.shortValue() may also be used.
Essentially x >> n is an arithmetic shift right. This is the equivalent of division by 2. In performing this operation the sign of the integer is preserved. In a negative number the most significant bit (msb), or leftmost bit, is set to 1. Using x >> n preserves the msb bit and will shift in a '1' for numbers where the msb is set prior to the shift operation or a '0' if the msb is clear prior to the shift operation. The x >>> n operator on the other hand always shifts in a '0' to the msb regardless of the value of the msb prior to the shift opertion. Here is a short piece of code demonstrating the effect of the two operations. https://code.sololearn.com/ca0a168a23a6