10

I'm a little confused now by java left shift operation,

1<<31 =  0x80000000  --> this I can understand

But

1<<32 =  1       Why is this?
1<<33 =  2       

Looks like more shifting values, modulus 32 of the value is taken.

Thanks everybody for the replying and giving the quote from JLS.

I just want to know more. Any idea of the reason why it's designed in this way? Or is it just some convention? Apparently C doesn't have this quirk?

Thanks to @paxdiablo. Looks like C declares this behaviour undefined.

I have some personal assumption here:

ARM architecture Reference Manual A7.1.38

Syntax LSL Rd, Rm, #immed_5

where:

Rd Is the register that stores the result of the operation.

Rm Is the register containing the value to be shifted.

immed_5 Specifies the shift amount, in the range 0 to 31.

On instruction level, the immeidate immed_5 takes only 5 bits to avoid meaningless operations so as to save some instruction space. I guess high level languages just unitize this convention to avoid meaningless effort when compile to instructions.

Bill Randerson
  • 1,028
  • 1
  • 11
  • 29

2 Answers2

14

As per the Java Language Specification 15.19. Shift Operators (slightly paraphrased):

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 & with the mask value 0x1f ,or 0b11111. The shift distance actually used is therefore always in the range 0 to 31, inclusive.

That means that (for example) 33, being the 6-bit binary 100001, is reduced to the 5-bit 00001 before being used. So x << 33 is identical to x << 1.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    Thanks @Paxdiablo. Do you have any idea of the reason why it's designed in this way? Or is it just some convention? Apparently C doesn't have this quirk? – Bill Randerson Dec 10 '15 at 05:21
  • @Bill, C has a much ***worse*** quirk, to wit `If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.` Java fully specified quite a few behaviours that C didn't, a sort of a clean-up made from experience. In terms of why it won't shift 32 bits and just set the value to zero, it's hard to see a use case for that. Bit shifting tends to be used for extracting/setting bits, and you can't extract any useful bits from a value you have shifted into oblivion :-) – paxdiablo Dec 10 '15 at 05:24
-1
System.out.println(Integer.toBinaryString(1 << 32)); 

Shifts binary 1(10) by 32 times to the left. Hence: 1 in decimal

System.out.println(Integer.toBinaryString(1 << 33)); 

Now, int is of 4 bytes,hence 32 bits. So when you do shift by 33, it's equivalent to shift by 1. Hence : 2 in decimal

slavoo
  • 5,798
  • 64
  • 37
  • 39
  • If a 32-bit binary 1 was _actually_ shifted 32-bits left, the result would be *zero,* not one. Maybe you're thinking of rotation? – paxdiablo Dec 10 '15 at 04:53