Java Language Specification — Math Operations Source: https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html 1. Spec Reference JLS Chapter 15 : Expressions — https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html JLS §15.14 : Postfix Expressions (x++, x--) JLS §15.15 : Unary Operators (+x, -x, ++x, --x, ~, !) JLS §15.17 : Multiplicative Operators (*, /, %) JLS §15.18 : Additive Operators (+, -) JLS §15.19 : Shift Operators (<<, >>, >>>) JLS §15.20 : Relational Operators (<, >, <=, >=, instanceof) JLS §15.21 : Equality Operators (==, !=) JLS §15.22 : Bitwise and Logical Operators (&, |, ^) JLS §15.23 : Conditional-And Operator (&&) JLS §15.24 : Conditional-Or Operator (||) JLS §15.25 : Conditional Operator (? :) JLS §15.26 : Assignment Operators (=, +=, -=, etc.) JLS §4.2.2 : Integer Operations JLS §4.2.4 : Floating-Point Operations -- JLS §15: Operator Precedence (high to low) --
-- 1. Postfix: expr++ expr--
-- 2. Unary: ++expr --expr +expr -expr ~ !
-- 3. Cast: (type) expr
-- 4. Multiplicative: * / %
-- 5. Additive: + -
-- 6. Shift: << >> >>>
-- 7. Relational: < > <= >= instanceof
-- 8. Equality: == !=
-- 9. Bitwise AND: &
-- 10. Bitwise XOR: ^
-- 11. Bitwise OR: |
-- 12. Logical AND: &&
-- 13. Logical OR: ||
-- 14. Ternary: ? :
-- 15. Assignment: = += -= *= /= %= &= |= ^= <<= >>= >>>=
-- JLS §15.17: Multiplicative Operators --
MultiplicativeExpression:
UnaryExpression
MultiplicativeExpression * UnaryExpression
MultiplicativeExpression / UnaryExpression
MultiplicativeExpression % UnaryExpression
-- JLS §15.18: Additive Operators --
AdditiveExpression:
MultiplicativeExpression
AdditiveExpression + MultiplicativeExpression
AdditiveExpression - MultiplicativeExpression
-- JLS §15.19: Shift Operators --
ShiftExpression:
AdditiveExpression
ShiftExpression << AdditiveExpression
ShiftExpression >> AdditiveExpression
ShiftExpression >>> AdditiveExpression
-- JLS §15.22: Bitwise and Logical Operators --
AndExpression:
EqualityExpression
AndExpression & EqualityExpression
ExclusiveOrExpression:
AndExpression
ExclusiveOrExpression ^ AndExpression
InclusiveOrExpression:
ExclusiveOrExpression
InclusiveOrExpression | ExclusiveOrExpression
-- JLS §15.26: Assignment Operators --
AssignmentOperator: one of
= *= /= %= += -= <<= >>= >>>= &= ^= |=
-- JLS §15.25: Conditional (Ternary) Operator --
ConditionalExpression:
ConditionalOrExpression
ConditionalOrExpression ? Expression : ConditionalExpression
ConditionalOrExpression ? Expression : LambdaExpression
-- JLS §15.14.2: Postfix Increment Operator --
PostfixExpression:
Primary
ExpressionName
PostIncrementExpression
PostDecrementExpression
PostIncrementExpression:
PostfixExpression ++
PostDecrementExpression:
PostfixExpression --
3. Core Rules & Constraints 3.1 Operator Associativity (JLS §15) Most binary operators are left-associative : a - b - c = (a - b) - c. Assignment operators are right-associative : a = b = c = a = (b = c). The ternary ? : is right-associative . Precedence is fixed; use parentheses to override. 3.2 Integer Arithmetic Rules (JLS §4.2.2) Integer division truncates toward zero: 7 / 2 = 3, -7 / 2 = -3. Modulo % satisfies: (a/b)*b + (a%b) == a for all a, b where b != 0. Division by zero for integer types → ArithmeticException. No implicit overflow detection; result wraps around (two's complement). The % result has the same sign as the dividend (not divisor). 3.3 Floating-Point Arithmetic Rules (JLS §4.2.4) IEEE 754-2019 standard. 1.0 / 0.0 → +Infinity (no exception). 0.0 / 0.0 → NaN. NaN comparison with any value (including itself) returns false, except !=. Java uses round-to-nearest-even as default rounding mode. 3.4 Shift Operator Rules (JLS §15.19) Left shift <<: a << n = a * 2^n (modular). Signed right shift >>: fills with sign bit (arithmetic shift). Unsigned right shift >>>: fills with 0 (logical shift). RHS is masked: int << n uses n % 32; long << n uses n % 64. Shift operators promote operands to at least int. 3.5 Bitwise Operator Rules (JLS §15.22) & (AND), | (OR), ^ (XOR), ~ (NOT — unary complement). Applied to boolean: no short-circuit (evaluates both sides). Applied to integers: bitwise operation on all bits. ~n = -n - 1 for any integer n (bitwise NOT = two's complement inversion). 3.6 Short-Circuit Evaluation (JLS §15.23, §15.24) &&: right side evaluated only if left side is true. ||: right side evaluated only if left side is false. This is critical for null-safe patterns: obj != null && obj.method(). 4. Type Rules Unary numeric promotion: byte, short, char → int. Binary numeric promotion: Either double → both double. Else either float → both float. Else either long → both long. Otherwise → both int. 4.2 Integer vs Floating-Point Division int / int → integer division (no fractional part). int / double → double division (one operand widened). Force floating-point division: (double) a / b or a * 1.0 / b. 4.3 Compound Assignment Type Rules (JLS §15.26.2) x += e is equivalent to x = (T)(x + e) where T is the type of x. Implicit narrowing cast is performed: byte b = 5; b += 3; is legal (equivalent to b = (byte)(b+3)). This makes compound assignments on byte/short legal without explicit cast. 4.4 Math Class (Static Methods) Math.abs(n): absolute value. Note: Math.abs(Integer.MIN_VALUE) returns Integer.MIN_VALUE (overflow!). Math.max(a, b) / Math.min(a, b): maximum/minimum. Math.pow(a, b): a^b as double. Math.sqrt(n): square root as double. sqrt(-1.0) → NaN. Math.log(n): natural logarithm. log(0) → -Infinity. Math.log10(n): base-10 logarithm. Math.floor(d), Math.ceil(d), Math.round(d): rounding functions. Math.PI, Math.E: double constants. 5. Behavioral Specification 5.1 Pre/Post Increment Behavior (JLS §15.14, §15.15) x++: evaluates to the old value of x, then increments x. ++x: increments x first, then evaluates to the new value. x-- and --x analogously for decrement. These operators have side effects and should not be used with aliased expressions. 5.2 Integer Modulo Semantics (JLS §15.17.3) a % b where a and b are integers: 5 % 3 = 2 -5 % 3 = -2 (result sign follows dividend) 5 % -3 = 2 -5 % -3 = -2 For floating-point %: uses Math.IEEEremainder() for IEEE remainder; % operator gives "truncated" remainder. 5.3 Bitwise Shift Behavior (JLS §15.19) For int x = 1: x << 1 = 2 x << 31 = Integer.MIN_VALUE (sign bit set) x << 32 = 1 (32 mod 32 = 0, no shift) -1 >> 1 = -1 (arithmetic shift right, fills with 1) -1 >>> 1 = Integer.MAX_VALUE (logical shift right, fills with 0) 5.4 IEEE 754 Rounding Modes Java always uses round-to-nearest-even (banker's rounding) for floating-point. strictfp was used to force IEEE 754 strict evaluation (obsolete since Java 17). FPU fused multiply-add (FMA): Math.fma(a, b, c) = a*b+c with single rounding (Java 9+). 6. Defined vs Undefined Behavior Expression Result Reference 7 / 0 (int) ArithmeticException JLS §15.17.2 7.0 / 0.0 Infinity JLS §4.2.4 0 / 0 (int) ArithmeticException JLS §15.17.2 0.0 / 0.0 NaN JLS §4.2.4 7 % 0 (int) ArithmeticException JLS §15.17.3 Integer.MAX_VALUE + 1 -2147483648 (wrap) JLS §4.2.2 1 << 32 1 (shift mod 32) JLS §15.19 ~0 -1 JLS §15.15.5 Math.abs(Integer.MIN_VALUE) Integer.MIN_VALUE java.lang.Math API -7 % 3 -1 JLS §15.17.3 true & false false (no short-circuit) JLS §15.22.2 true && false false (short-circuit) JLS §15.23
7. Edge Cases from Spec 7.1 Integer Overflow Silently Wraps int max = Integer . MAX_VALUE ;
System . out . println ( max + 1 ); // -2147483648 (no exception)
System . out . println ( max * 2 ); // -2 (wrap)
// Safe: Math.addExact throws ArithmeticException on overflow
int safe = Math . addExact ( max , 1 ); // throws ArithmeticException
7.2 Shift by Modular Amount int x = 1 ;
System . out . println ( x << 32 ); // 1 (not 0! — 32 mod 32 == 0)
System . out . println ( x << 33 ); // 2 (33 mod 32 == 1)
long y = 1L ;
System . out . println ( y << 64 ); // 1L (64 mod 64 == 0)
7.3 Compound Assignment with Narrowing byte b = 100 ;
b += 50 ; // legal: equivalent to b = (byte)(b + 50) = (byte)150 = -106
System . out . println ( b ); // -106 (not a compile error!)
7.4 String Concatenation Operator Precedence System . out . println ( 1 + 2 + " apples" ); // "3 apples" (1+2=3, then concat)
System . out . println ( "apples: " + 1 + 2 ); // "apples: 12" (concat left to right)
System . out . println ( "apples: " + ( 1 + 2 )); // "apples: 3"
7.5 Short-Circuit Evaluation Side Effects int count = 0 ;
boolean result = true || ( ++ count > 0 ); // right side NOT evaluated
System . out . println ( count ); // 0 (not 1)
boolean result2 = false && ( ++ count > 0 ); // right side NOT evaluated
System . out . println ( count ); // still 0
7.6 Math.abs Overflow System . out . println ( Math . abs ( Integer . MIN_VALUE )); // -2147483648 (overflow!)
System . out . println ( Math . abs ( Long . MIN_VALUE )); // -9223372036854775808 (overflow!)
// Use Math.absExact() (Java 15+) for overflow detection:
Math . absExact ( Integer . MIN_VALUE ); // throws ArithmeticException
8. Version History Java Version Change JEP/Reference Java 1.0 All basic operators; Math class; IEEE 754 JLS 1st ed. Java 5 Math.log10(), improved precision JDK 5 API Java 8 Math.addExact(), Math.subtractExact(), Math.multiplyExact(), Math.toIntExact() JDK 8 API Java 9 Math.fma() (fused multiply-add); Math.multiplyHigh() JEP 215 Java 14 Math.absExact() (Java 15 actually) JDK API Java 15 Math.absExact(int), Math.absExact(long) JDK-15 API Java 17 strictfp obsolete — IEEE 754 strict is now default for all JEP 306 Java 18 Math.clamp() (preview in discussions) JDK-21 Java 21 Math.clamp(value, min, max) — clamp to range JDK-21 API
9. Implementation-Specific Behavior (JVM-Specific) 9.1 JVM Bytecode for Arithmetic Operation int bytecode long bytecode float double add iadd ladd fadd dadd sub isub lsub fsub dsub mul imul lmul fmul dmul div idiv ldiv fdiv ddiv rem irem lrem frem drem neg ineg lneg fneg dneg shl ishl lshl — — shr ishr lshr — — ushr iushr lushr — — and iand land — — or ior lor — — xor ixor lxor — —
9.2 JIT Optimization of Arithmetic HotSpot JIT replaces Math.abs(x) with CPU abs instruction on x86. Integer multiply by 2 may compile to shl 1 (left shift). Division by constant is replaced by multiply-and-shift sequence. Overflow checks (Math.addExact) are intrinsified by JIT. 9.3 Floating-Point Hardware x86/x64 JVMs use SSE2/AVX for float and double operations. Prior to Java 17, x87 FPU could produce 80-bit intermediate results; strictfp forced 64-bit. Java 17+ (JEP 306): always uses SSE2+; strictfp is a no-op. 9.4 Math.random() vs ThreadLocalRandom Math.random() uses a shared Random instance — contention under parallelism. ThreadLocalRandom.current().nextDouble() is preferred for concurrent use. Math.random() is seeded from System.nanoTime() by default. 10. Spec Compliance Checklist 11. Official Examples (Compilable Java 21 Code) // Example 1: Arithmetic Operators
// File: ArithmeticOps.java
public class ArithmeticOps {
public static void main ( String [] args ) {
int a = 17 , b = 5 ;
System . out . println ( "a + b = " + ( a + b )); // 22
System . out . println ( "a - b = " + ( a - b )); // 12
System . out . println ( "a * b = " + ( a * b )); // 85
System . out . println ( "a / b = " + ( a / b )); // 3 (integer division)
System . out . println ( "a % b = " + ( a % b )); // 2
// Negative modulo
System . out . println ( "-17 % 5 = " + ( - 17 % 5 )); // -2 (sign of dividend)
System . out . println ( "17 % -5 = " + ( 17 % - 5 )); // 2
// Pre/post increment
int x = 10 ;
System . out . println ( x ++ ); // 10 (old value)
System . out . println ( x ); // 11
System . out . println ( ++ x ); // 12 (new value)
System . out . println ( x ); // 12
// Overflow
int max = Integer . MAX_VALUE ;
System . out . println ( "MAX + 1 = " + ( max + 1 )); // -2147483648 (wrap)
// Checked arithmetic (Java 8+)
try {
Math . addExact ( Integer . MAX_VALUE , 1 );
} catch ( ArithmeticException e ) {
System . out . println ( "Overflow: " + e . getMessage ());
}
// clamp (Java 21+)
int value = 150 ;
int clamped = Math . clamp ( value , 0 , 100 );
System . out . println ( "clamp(150, 0, 100) = " + clamped ); // 100
}
}
// Example 2: Bitwise and Shift Operators
// File: BitwiseOps.java
public class BitwiseOps {
public static void main ( String [] args ) {
int a = 0b1100 ; // 12
int b = 0b1010 ; // 10
System . out . printf ( "a & b = %4d (%s)%n" , a & b , Integer . toBinaryString ( a & b )); // 8 1000
System . out . printf ( "a | b = %4d (%s)%n" , a | b , Integer . toBinaryString ( a | b )); // 14 1110
System . out . printf ( "a ^ b = %4d (%s)%n" , a ^ b , Integer . toBinaryString ( a ^ b )); // 6 0110
System . out . printf ( "~a = %4d%n" , ~ a ); // -13
// Shifts
int n = 1 ;
System . out . println ( "1 << 3 = " + ( n << 3 )); // 8
System . out . println ( "8 >> 1 = " + ( 8 >> 1 )); // 4
System . out . println ( "-8 >> 1 = " + ( - 8 >> 1 )); // -4 (arithmetic: fill with 1)
System . out . println ( "-8 >>> 1 = " + ( - 8 >>> 1 )); // large positive (logical: fill with 0)
// Useful bit tricks
int flags = 0 ;
int FLAG_A = 1 << 0 ; // bit 0
int FLAG_B = 1 << 1 ; // bit 1
int FLAG_C = 1 << 2 ; // bit 2
flags |= FLAG_A ; // set FLAG_A
flags |= FLAG_C ; // set FLAG_C
System . out . println ( "FLAG_A set: " + (( flags & FLAG_A ) != 0 )); // true
System . out . println ( "FLAG_B set: " + (( flags & FLAG_B ) != 0 )); // false
flags ^= FLAG_A ; // toggle FLAG_A
System . out . println ( "FLAG_A after toggle: " + (( flags & FLAG_A ) != 0 )); // false
}
}
// Example 3: Math Class Usage
// File: MathDemo.java
public class MathDemo {
public static void main ( String [] args ) {
// Basic Math
System . out . println ( Math . abs ( - 42 )); // 42
System . out . println ( Math . abs ( Integer . MIN_VALUE )); // -2147483648 (edge case!)
System . out . println ( Math . max ( 10 , 20 )); // 20
System . out . println ( Math . min ( 10 , 20 )); // 10
// Powers and roots
System . out . println ( Math . pow ( 2 , 10 )); // 1024.0
System . out . println ( Math . sqrt ( 144 )); // 12.0
System . out . println ( Math . cbrt ( 27 )); // 3.0
System . out . println ( Math . sqrt ( - 1 )); // NaN
// Rounding
System . out . println ( Math . floor ( 3.7 )); // 3.0
System . out . println ( Math . ceil ( 3.2 )); // 4.0
System . out . println ( Math . round ( 3.5 )); // 4
System . out . println ( Math . round ( 3.4 )); // 3
System . out . println ( Math . round ( - 3.5 )); // -3 (rounds toward +infinity)
// Logarithms and trig
System . out . println ( Math . log ( Math . E )); // 1.0
System . out . println ( Math . log10 ( 1000 )); // 3.0
System . out . printf ( "sin(90°) = %.2f%n" , Math . sin ( Math . PI / 2 )); // 1.00
System . out . printf ( "cos(0°) = %.2f%n" , Math . cos ( 0 )); // 1.00
// Constants
System . out . println ( "PI = " + Math . PI );
System . out . println ( "E = " + Math . E );
// FMA (Java 9+) — fused multiply-add, single rounding
double fma = Math . fma ( 2.0 , 3.0 , 4.0 ); // 2.0*3.0 + 4.0 = 10.0
System . out . println ( "fma(2, 3, 4) = " + fma );
// clamp (Java 21)
System . out . println ( Math . clamp ( 5.5 , 0.0 , 10.0 )); // 5.5
System . out . println ( Math . clamp ( - 3.0 , 0.0 , 10.0 )); // 0.0
System . out . println ( Math . clamp ( 15.0 , 0.0 , 10.0 )); // 10.0
}
}
// Example 4: Operator Precedence and Short-Circuit
// File: OperatorPrecedence.java
public class OperatorPrecedence {
static int sideEffect ( String label , int value ) {
System . out . println ( "Evaluating: " + label );
return value ;
}
public static void main ( String [] args ) {
// Precedence: * before +
int result = 2 + 3 * 4 ;
System . out . println ( result ); // 14 (not 20)
// Left-to-right evaluation for + with strings
System . out . println ( 1 + 2 + "3" ); // "33" (1+2=3, then "3"+"3"="33")
System . out . println ( "1" + 2 + 3 ); // "123" (string concat left-to-right)
System . out . println ( "1" + ( 2 + 3 )); // "15" (parentheses override)
// Short-circuit: second operand not evaluated
System . out . println ( "--- Short-circuit AND ---" );
boolean r1 = false && ( sideEffect ( "right-AND" , 1 ) > 0 ); // right NOT evaluated
System . out . println ( "result: " + r1 );
System . out . println ( "--- Short-circuit OR ---" );
boolean r2 = true || ( sideEffect ( "right-OR" , 1 ) > 0 ); // right NOT evaluated
System . out . println ( "result: " + r2 );
System . out . println ( "--- Non-short-circuit ---" );
boolean r3 = false & ( sideEffect ( "right-&" , 1 ) > 0 ); // right IS evaluated
System . out . println ( "result: " + r3 );
// Ternary operator
int x = 7 ;
String category = x > 5 ? "big" : x > 2 ? "medium" : "small" ; // right-assoc
System . out . println ( category ); // "big"
// Assignment operators
int n = 10 ;
n += 5 ; System . out . println ( n ); // 15
n -= 3 ; System . out . println ( n ); // 12
n *= 2 ; System . out . println ( n ); // 24
n /= 4 ; System . out . println ( n ); // 6
n %= 4 ; System . out . println ( n ); // 2
n <<= 3 ; System . out . println ( n ); // 16
n >>= 1 ; System . out . println ( n ); // 8
}
}
// Example 5: Floating-Point Arithmetic
// File: FloatArithmetic.java
public class FloatArithmetic {
public static void main ( String [] args ) {
// Precision issues
System . out . println ( 0.1 + 0.2 ); // 0.30000000000000004
System . out . println ( 0.1 + 0.2 == 0.3 ); // false!
// Use epsilon comparison
double a = 0.1 + 0.2 ;
double b = 0.3 ;
double eps = 1e-9 ;
System . out . println ( Math . abs ( a - b ) < eps ); // true
// Use BigDecimal for exact decimal arithmetic
java . math . BigDecimal bd1 = new java . math . BigDecimal ( "0.1" );
java . math . BigDecimal bd2 = new java . math . BigDecimal ( "0.2" );
System . out . println ( bd1 . add ( bd2 )); // 0.3 (exact)
// Rounding modes
double val = 2.5 ;
System . out . println ( Math . round ( val )); // 3 (rounds to nearest, ties up)
System . out . println ( Math . rint ( val )); // 2.0 (rounds to nearest, ties to even)
System . out . println ( Math . round ( 3.5 )); // 4
System . out . println ( Math . rint ( 3.5 )); // 4.0 (even)
System . out . println ( Math . rint ( 4.5 )); // 4.0 (even, not 5!)
// Special values
double posInf = 1.0 / 0.0 ;
double negInf = - 1.0 / 0.0 ;
double nan = 0.0 / 0.0 ;
System . out . println ( posInf > Double . MAX_VALUE ); // true
System . out . println ( negInf < - Double . MAX_VALUE ); // true
System . out . println ( nan == nan ); // false
System . out . println ( Double . isNaN ( nan )); // true
System . out . println ( posInf + 1 ); // Infinity
System . out . println ( posInf - posInf ); // NaN
}
}
Section Topic URL JLS §4.2.2 Integer Operations https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.2.2 JLS §4.2.4 Floating-Point Operations https://docs.oracle.com/javase/specs/jls/se21/html/jls-4.html#jls-4.2.4 JLS §15.14 Postfix Expressions https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.14 JLS §15.17 Multiplicative Operators https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.17 JLS §15.18 Additive Operators https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.18 JLS §15.19 Shift Operators https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.19 JLS §15.22 Bitwise Operators https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.22 JLS §15.23 Conditional-And https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.23 JLS §15.26 Assignment Operators https://docs.oracle.com/javase/specs/jls/se21/html/jls-15.html#jls-15.26 JEP 306 Restore Always-Strict FP https://openjdk.org/jeps/306
In this topic