Bits shifting, getting incorrect value - java

For this shifting:
System.out.println(0b10000000_00000000_00000000_00000001>>>32);
I'm getting this output value:
-2147483647
Is it correct?

The JLS says:
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.
Since 32 is 100000 in binary, only the five lowest bits are taken, which means you are not shifting the left-hand operand at all.
In other words, 0b10000000_00000000_00000000_00000001>>>32 is equivalent to 0b10000000_00000000_00000000_00000001>>>0.
Hence the result is 0b10000000_00000000_00000000_00000001.

Related

What if a cast operator is used in shift operators

The JLS says that
The type of the shift expression is the promoted type of the left-hand
operand.
If the promoted type of the left-hand operand is int, then 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.
If the promoted type of the left-hand operand is long, then only the
six 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 0x3f
(0b111111). The shift distance actually used is therefore always in
the range 0 to 63, inclusive.
So if I explicitly make a byte and a short operand using the cast operator like (byte)100<<100 and (short)100<<100, what will be the usable bits of the right operand?
Edit: Does an operand undergo a numeric promotion (unary/binary) if it has already been converted to a different (smaller) type using a casting operator? If this is the case, how would you explain the expression having byte variables b1 = (byte)(b2 + b3) because after the cast conversion, the byte result will probably convert to int as per the numeric promotion?
The Java 8 JLS also states in §5.6.1:
5.6.1. Unary Numeric Promotion
Some operators apply unary numeric promotion to a single operand, which must produce a value of a numeric type:
...
Otherwise, 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).
...
Thus, if we take the following expression:
int i = ...
short s = (short) i << 2;
Will result in a compiler error:
Main.java:4: error: incompatible types: possible lossy conversion from int to short
short s = (short) i << 2;
Ideone demo
This is due to the fact that the cast binds to the first argument of the shift, not the whole expression. Here is the whole expression with explicit parenthesis:
short s = ((byte) i) << 2;
Whereas
int i = ...;
int j = (short) i << 2;
Will successfully compile.
Ideone demo
So the effective bits to use for anything < int is the same as for int (5 bits) since they are upcasted to int automatically.
If you cast the result of the whole expression to, e.g. short (short s = (short) (i << 2), then there is no automatism that takes place in the compiler. But Bohemian's answer gives a logical bound as to what bits of the right hand operator will effectively influence the value after the cast.
In newer JLS versions, the section has been reworded. For example, in Java 14 JLS, §5.6 we find (the section is shortened for breviety, I recommend reading the whole paragraph to get the full context):
5.6. Numeric Contexts
Numeric contexts apply to the operands of arithmetic operators, array creation and access expressions, conditional expressions, and the result expressions of switch expressions.
An expression appears in a numeric arithmetic context if the expression is one of the following:
...
An operand of a shift operator <<, >>, or >>> (§15.19). Operands of these shift operators are treated separately rather than as a group. A long shift distance (right operand) does not promote the value being shifted (left operand) to long.
...
Numeric promotion determines the promoted type of all the expressions in a numeric context. The promoted type is chosen such that each expression can be converted to the promoted type, and, in the case of an arithmetic operation, the operation is defined for values of the promoted type. The order of expressions in a numeric context is not significant for numeric promotion. The rules are as follows:
...
Next, widening primitive conversion (§5.1.2) and narrowing primitive conversion (§5.1.3) are applied to some expressions, according to the following rules:
...
Otherwise, none of the expressions are of type double, float, or long. In this case, the kind of context determines how the promoted type is chosen.
In a numeric arithmetic context or a numeric array context, the promoted type is int, and any expressions that are not of type int undergo widening primitive conversion to int.
In a numeric choice context, the following rules apply:
...
Otherwise, the promoted type is int, and all the expressions that are not of type int undergo widening primitive conversion to int.
...
The number of bits of the maximum usable shift distance is given by log2n, where n is the number of bits used to represent values of the left hand type.
byte has 8 bits. log28 is 3. So only the right most 3 bits are used, giving a shift value in the range 0-7.
short has 16 bits. log216 is 4. So only the right most 4 bits are used, giving a shift value in the range 0-15.

Java Bitwise shift operator with Negative Operands

Operand1 ShiftOperator Operand2
Shift Rule
If either of the Operand is Negative don't forget to calculate its 2's complement since Negative integers is stored in Memory using 2's complement
Mask Operand2 with 0x1F
Right shift
81814621>>-12 = 78
81814621>>>-12 = 78
OK!!
Right shift (Operand1 is NEGATIVE)
-81814621>>-12 = -79
-81814621>>>-12 = 4017
Why different?
Left shift
21<<-12 = 22020096
-21<<-12 = -22020096
Unlike Right shift no matter Operand1 is Positive/Negative
only sign get changed instead value
Thanks for all of your support! now i have a better idea on it...:)
Wherever you got that from, it's wrong. Operand2 cannot possibly be either negative or have anything at all in its leftmost five bits after masking it with 0x1F. There is nothing in the Java Language Specification about taking the twos-complement of the shift distance, or using its left-most five bits. Read what it really says. Don't rely on arbitrary sources, or just make it up.
EDIT -81814621 is 0xFFFFFFFFFB1F9BA3, -12 is 0xFFFFFFFFFFFFFFF4, bottom five bits of that is 0x14 or 20, right shift the first operand by 20 gives 0xFFFFFFFFFFFFFFB1, which is -79.
The "rule" about what to do with the right-hand side operator of the shift is there because the list of values of the right operand that truly make sense is very short: for ints the range is from zero to 31, inclusive; for longs, it is zero to 63.
All other values of int on the right-hand side need to be converted to a value in the specified range. The "rule" spells out the process - i.e. re-interpreting the number as positive (that's what the two's complement is about), then masking off the higher bits, keeping the last five.
In contrast, the left operand can retain its full range. The only difference that you are experiencing has to do with the difference between >> and >>>, that is, between an operator that interprets the left-hand side operand as signed for shifting, and the one that interprets it as unsigned.
The purpose behind the >>> operator is explained in this answer. In your example, when you right-shift a negative number with the two operators, the >> leaves the number negative by sigh-extending it (i.e. shifting ones on the left) while >>> makes it positive by shifting in zeros.

Is java bit shifting circular?

I have this behavior using Java:
int b=16;
System.out.println(b<<30);
System.out.println(b<<31);
System.out.println(b<<32);
System.out.println(b<<33);
output:
0
0
16
32
Is java bit shift circular? IF not, why I get 0 when b<<30 and 16 when b<<32?
Bit shifting is not circular; for bit-shifting ints, Java only uses the 5 least-significant bits, so that (b << 0) is equivalent to (b << 32) (is equivalent to (b << 64), etc.). You can simply take the bit-shifting amount and take the remainder when dividing by 32.
Something similar occurs for bit-shifting longs, where Java only uses the 6 least-significant bits, so that (aLong << 0) is equivalent to (aLong << 64).
Section 15.19 of the JLS talks about this:
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.
If the promoted type of the left-hand operand is long, then only the six 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 0x3f (0b111111). The shift distance actually used is therefore always in the range 0 to 63, inclusive.
(emphasis mine)
(You can't bit-shift floats or doubles, and attempting to bit-shift a short or a byte would be subject the value to unary numeric promotion to an int anyway.)
You get 0 from 16 << 30, because the 1-bit from 16
00000000 00000000 00000000 00010000
gets shifted off the end of the int and gets discarded.
// Discarded - Result-----------------------------
(00000100) 00000000 00000000 00000000 00000000
No, it's not circular shift. It's normal left-shift. It's just that, for int type left side operand, Java uses just 5 lower order bits of the right operand for shifting. This is as per JLS §15.9:
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, for 16 << 32, considering only 5 lower order bits of 32, the expression is equivalent to:
16 << 32 & 0x1f
which is equal to 16.

Shifting by Negative Numbers

I am pretty confused with this expression here. I am a Java programmer but I am not very well versed with bit manipulation.
I think I understand the below correctly:
Input : 1 << 10
Output: 0000000000000000000010000000000
For positive numbers, I think it is you move 1 by 10 bits.
The confusion is when I have the below:
int val = -10 (binary representation : 1111111111111111111111111110110 )
Input : 1 << val
Output: 0000000010000000000000000000000
That would be really great if someone can explain me the meaning of left shifting or right shifting by negative number.
<< (and other shift operators) only takes 5 least significant bits of its right operand for int, and 6 for long, because it makes no sense to shift int by more than 31.
In your case it's 0b10110 = 22.
Therefore 1 << (-10) is equivalent to 1 << 22.
From the JLS, 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.
In other words,
1 << -10
is equivalent to:
1 << (-10 & 0x1f)
... which is
1 << 22

What does this bit shift operation means in Java RegularEnumSet implementation?

In RegularEnumSet implementation, there is a code:
elements = -1L >>> -universe.lengh
It uses a Long type integer to implement efficient EnumSet.
What is notable is that the right-hand operand of >>> is a negative figure.
I have tested and found that
int i = -1;
i >>> -3
has equivalent effect with
int i = 1;
i << 3;
So why bother to write in this ambiguous form?
From the "Java Language Specification", section 15.19, about shifting "If the promoted type of the left-hand operand is long, then only the six lowest-order bits of the right-hand operand are used as the shift distance. It is as if the right-and operand were subjected to a bitwise logical AND operator & with the mask value 0x3f. The shift distance actually used is therefore awlays 0 to 64, inclusive."
So, >>> -3 has equivalent effect as >>> 61, and -1L >>> -n equals -1L >>> (0x3f&-n)
Actually this seems to be the most effective way of producing a consecutive 1s in the lowest n-bits of a long integer.
First, note that the code you quoted uses -1L, not -1. Longs are unsigned, so -1L is equivalent to setting all the bits on the long, or getting the highest possible long number.
>>> -3 has equivalent effect with << 3
It doesn't. The unsigned right shift operator (>>>) shifts zeroes into the sign bit, while >> and << preserve the sign of the value being shifted, shifting 1 or 0 accordingly. That's why -1L >>> -3 is 7 (0111b) and 1L << 3 is 8 (1000b).

Categories