Why does Java mask shift operands with 0x1F?

守給你的承諾、 提交于 2019-12-04 00:18:29

问题


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

回答1:


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.




回答2:


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



来源:https://stackoverflow.com/questions/15708760/why-does-java-mask-shift-operands-with-0x1f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!