First example
Let us analyze what you have done. The first example is
((long) Math.pow(2, 31)) - 1;
This means that you first compute Math.pow(2, 31)
which yields
2.147_483_648 E9
After that you cast to long
. Note that long
has enough place for this value, so it represents it as
2_147_483_648
Then you subtract 1
and get
2_147_483_647
Second example
Let's now see what the second example does. Your wrote
(int) Math.pow(2, 31) - 1
This is interpreted as
((int) Math.pow(2, 31)) - 1
So the same as before but with a cast to int
instead of long
. Now note that int
does not have enough place for the value. The biggest int
that can be represented is
2_147_483_647 // MAX_INTEGER
and thus you will also get exactly this value here. After that you subtract 1
and get
2_147_483_646
Correction
I think you thought that
(int) Math.pow(2, 31) - 1
evaluates to
(int) (Math.pow(2, 31) - 1)
but it doesn't. If you make this explicit you will indeed get
2_147_483_647
as expected.
Operator precedence
You can read about that in the Java Language Specification, refer to JLS§15.15 Unary Operators. Casting has precedence over operators like subtraction.
That is because casting is an unary operator whereas subtraction is binary. Unary has precedence over binary. The official documentation therefore gives the following table as overview:
+----------------------------------------------------------------+
| Operators | Precedence (top is high, bottom low) |
|-----------------------|----------------------------------------|
| postfix | expr++ expr-- |
| unary | ++expr --expr +expr -expr ~ ! |
| multiplicative | * / % |
| additive | + - |
| shift | << >> >>> |
| relational | < > <= >= instanceof |
| equality | == != |
| bitwise AND | & |
| bitwise exclusive OR | ^ |
| bitwise inclusive OR | | |
| logical AND | && |
| logical OR | || |
| ternary | ? : |
| assignment | = += -= *= /= %= &= ^= |= <<= >>= >>>= |
+----------------------------------------------------------------+
Casting is of course part of the unary category.