Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Java mask shift operands with 0x1F?

In Java:

(0xFFFFFFFF <<  1) = 0xFFFFFFFE = 0b1111111111111110
                :         :               :
(0xFFFFFFFF << 30) = 0xE0000000 = 0b1110000000000000
(0xFFFFFFFF << 30) = 0xC0000000 = 0b1100000000000000
(0xFFFFFFFF << 31) = 0x80000000 = 0b1000000000000000

However:

(0xFFFFFFFF << 32) = 0xFFFFFFFF = 0b1111111111111111

Logically this makes no sense, but what I believe to be happening is Java performing an operation similar to:

a << (b % Integer.SIZE) [edit, apparently:] a << (b & 0x1F)

This applies to >> and >>>, too.

Obviously shifting by >= 32 (in the case of an Integer) removes all data from the data-type, but there are times when this is useful. For example:

int value = 0x3F43F466; // any value
int shift = 17; // any value >= 0
int carry = value & (-1 << (Integer.SIZE - shift));
if (carry > 0)
    ; // code...

Of course this can be fixed, but finding these bugs can be quite time consuming (I just spent hours tracking a similar one down). So, my question: Is there reason for not returning the logical value when shifting all bits out?

UPDATE:

I tried this in C99, using the following:

#include<stdio.h>
main()
{
   int i, val;
   for (i = 0; i <=36; i++) {
       val = (-1 << i);
       printf("%d :\t%d\n", i, val);
   }
}

I found that it behaves the same as Java, masking i & 0x1F, whereas it provides a warning at compilation when given a constant value:

warning: left shift count >= width of type
like image 538
azz Avatar asked Mar 29 '13 17:03

azz


People also ask

What is<< and>> in Java?

Java supports two types of right shift operators. The >> operator is a signed right shift operator and >>> is an unsigned right shift operator. The left operands value is moved right by the number of bits specified by the right operand.

What is the<< operator Java?

Left shift operator shifts the bits of the number towards left a specified number of positions. The symbol for this operator is <<.

How does bit shifting work in Java?

The bit pattern is given by the left-hand operand, and the number of positions to shift by the right-hand operand. The unsigned right shift operator " >>> " shifts a zero into the leftmost position, while the leftmost position after ">>" depends on sign extension.


2 Answers

Sure, there is: it's how most processors (specifically including x86) implement bit shifting, and to do what you want -- to check if the shift is greater than 32, and if so, return zero -- requires a branch, which can be expensive on modern CPUs. It's not just "annoying," it can slow things down by orders of magnitude.

In short, doing what you want would add significant overhead to an operation that is expected to be blazing fast by high-performance code.

For reference, the logic isn't exactly the same as %, it's a mask. See JLS 15.19 for details:

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.

like image 150
Louis Wasserman Avatar answered Sep 28 '22 06:09

Louis Wasserman


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

to put it simply 0xFFFFFFFF << 32 is equivalnt to 0xFFFFFFFF << (32 & 0x1f) is equivalent to 0xFFFFFFFF << 0

like image 43
Evgeniy Dorofeev Avatar answered Sep 28 '22 08:09

Evgeniy Dorofeev