Contents
- Basic Operations — abs, min, max, signum, clamp
- Power and Roots — pow, sqrt, cbrt, hypot
- Rounding — floor, ceil, round, rint
- Trigonometry, Logarithms, and Constants
- Random Numbers — Math.random() and ThreadLocalRandom
- Overflow-Safe Arithmetic — exact Methods and floorDiv
Math.abs(), Math.min(), and Math.max() are overloaded for int, long, float, and double. Math.signum() returns -1.0, 0.0, or 1.0 based on the sign of a double. Java 21 adds Math.clamp() to constrain a value within a range in one call:
// abs — works for int, long, float, double
System.out.println(Math.abs(-42)); // 42
System.out.println(Math.abs(-3.14)); // 3.14
System.out.println(Math.abs(0)); // 0
// Edge case: abs(Integer.MIN_VALUE) overflows and returns a negative number
System.out.println(Math.abs(Integer.MIN_VALUE)); // -2147483648 (same value!)
// Use Math.absExact() (Java 15+) to throw ArithmeticException instead
// Math.absExact(Integer.MIN_VALUE); // throws ArithmeticException
// min and max — overloaded for all numeric primitives
int smaller = Math.min(10, 20); // 10
long larger = Math.max(100L, 200L); // 200
double minD = Math.min(3.14, 2.71); // 2.71
// Chaining min/max for clamping (pre-Java 21)
int value = 150;
int clamped = Math.min(Math.max(value, 0), 100); // clamp to [0, 100] → 100
// Math.clamp() — Java 21+, cleaner clamping
int result = Math.clamp(value, 0, 100); // 100
long lRes = Math.clamp(300L, 0L, 255L); // 255
double dRes = Math.clamp(-1.5, 0.0, 1.0); // 0.0
// signum — returns -1.0, 0.0, or 1.0
System.out.println(Math.signum(-42.0)); // -1.0
System.out.println(Math.signum(0.0)); // 0.0
System.out.println(Math.signum(99.0)); // 1.0
// copySign — apply the sign of one value to the magnitude of another
double pos = Math.copySign(5.0, -1.0); // -5.0 (magnitude 5, sign of -1)
double neg = Math.copySign(5.0, 1.0); // 5.0
Math.pow(base, exp) computes arbitrary powers as a double. Math.sqrt() and Math.cbrt() provide square and cube roots. Math.hypot(x, y) computes the hypotenuse of a right triangle as √(x²+y²) without intermediate overflow:
// pow — base raised to the exponent, always returns double
double squared = Math.pow(3, 2); // 9.0
double cubed = Math.pow(2, 10); // 1024.0
double fraction = Math.pow(8, 1.0/3); // 2.0 (cube root via pow)
// Special pow cases
System.out.println(Math.pow(0, 0)); // 1.0 (defined by IEEE 754)
System.out.println(Math.pow(-1, 0.5)); // NaN (not a real number)
System.out.println(Math.pow(Double.POSITIVE_INFINITY, 2)); // Infinity
// sqrt — square root
double root = Math.sqrt(25.0); // 5.0
double sqr2 = Math.sqrt(2.0); // 1.4142135623730951
System.out.println(Math.sqrt(-1)); // NaN
// cbrt — cube root (handles negative inputs correctly)
double cbrt = Math.cbrt(27.0); // 3.0
double cbrtNeg = Math.cbrt(-8.0); // -2.0 (unlike pow, cbrt works with negatives)
// hypot — Euclidean distance, avoids overflow for large values
double hyp = Math.hypot(3.0, 4.0); // 5.0 (Pythagorean triple)
double hyp2 = Math.hypot(1e154, 1e154); // ~1.414e154 (no overflow; pow(1e154,2) would overflow)
// Integer power without double — use repeated multiplication or BigInteger.pow()
long pow2_32 = 1L << 32; // 4294967296 — fast integer powers of 2
// For arbitrary int exponents:
long intPow(long base, int exp) {
long result = 1;
for (int i = 0; i < exp; i++) result *= base;
return result;
}
// exp — e raised to the power x
double eToX = Math.exp(1); // 2.718281828459045 (e¹)
double eNeg = Math.exp(-1); // 0.36787944117144233
// expm1 — exp(x) - 1, more accurate for small x
double small = Math.expm1(0.0001); // ~0.00010000500016667084 (more precise than exp(0.0001)-1)
Java provides four rounding functions with distinct semantics: floor rounds toward negative infinity, ceil toward positive infinity, round uses half-up rounding and returns an integer type, and rint rounds to the nearest even integer (banker's rounding) and returns a double:
double pos = 2.7;
double neg = -2.7;
double half = 2.5;
// floor — round toward negative infinity (always ≤ input)
System.out.println(Math.floor(pos)); // 2.0
System.out.println(Math.floor(neg)); // -3.0
System.out.println(Math.floor(2.0)); // 2.0
// ceil — round toward positive infinity (always ≥ input)
System.out.println(Math.ceil(pos)); // 3.0
System.out.println(Math.ceil(neg)); // -2.0
System.out.println(Math.ceil(2.0)); // 2.0
// round — half-up, returns int (for float) or long (for double)
System.out.println(Math.round(2.4)); // 2 (long)
System.out.println(Math.round(2.5)); // 3 (half rounds up)
System.out.println(Math.round(-2.5)); // -2 (half rounds toward +∞)
System.out.println(Math.round(-2.6)); // -3
// rint — banker's rounding (round-half-to-even), returns double
System.out.println(Math.rint(2.5)); // 2.0 (2 is even, rounds down)
System.out.println(Math.rint(3.5)); // 4.0 (4 is even, rounds up)
System.out.println(Math.rint(2.4)); // 2.0
System.out.println(Math.rint(2.6)); // 3.0
// Truncation toward zero — cast to int
int truncated = (int) 2.9; // 2
int negTrunc = (int) -2.9; // -2 (toward zero, not toward -∞ like floor)
// Rounding to N decimal places
double value = 3.14159;
double rounded2dp = Math.round(value * 100.0) / 100.0; // 3.14
// Prefer BigDecimal.setScale() for financial rounding accuracy
// floorDiv and floorMod — integer division that rounds toward -∞
System.out.println(Math.floorDiv(7, 2)); // 3 (same as 7/2 for positives)
System.out.println(Math.floorDiv(-7, 2)); // -4 (7/2=-3 rounds down to -4)
System.out.println(Math.floorMod(7, 3)); // 1
System.out.println(Math.floorMod(-7, 3)); // 2 (always non-negative when divisor > 0)
Use Math.floorMod() instead of % when you need a non-negative remainder — the % operator can return negative values for negative dividends, which breaks modular arithmetic (e.g., wrapping array indices or clock arithmetic).
All trigonometric functions in Math work in radians, not degrees. Use Math.toRadians() and Math.toDegrees() to convert. Math.log() computes the natural logarithm, Math.log10() the base-10 logarithm, and Math.log1p() is numerically stable for values close to zero:
// Constants
System.out.println(Math.PI); // 3.141592653589793
System.out.println(Math.E); // 2.718281828459045
// Degree/radian conversion
double deg = 90.0;
double rad = Math.toRadians(deg); // 1.5707963267948966 (π/2)
double backToDeg = Math.toDegrees(Math.PI); // 180.0
// Trigonometric functions (input in radians)
System.out.println(Math.sin(Math.PI / 2)); // 1.0
System.out.println(Math.cos(Math.PI)); // -1.0 (not exactly, ~-1.0)
System.out.println(Math.tan(Math.PI / 4)); // 1.0 (45°)
// Inverse trig — return radians
double angle = Math.asin(1.0); // π/2 = 1.5707... (arcsin of 1)
double aCos = Math.acos(0.0); // π/2
double aTan = Math.atan(1.0); // π/4
// atan2(y, x) — angle of vector (x, y) from origin, handles quadrant correctly
double theta = Math.atan2(1.0, 1.0); // π/4 = 45°
double theta2 = Math.atan2(-1.0, -1.0); // -3π/4 = -135°
// Hyperbolic functions
double sinh = Math.sinh(1.0); // (e¹ - e⁻¹) / 2
double cosh = Math.cosh(1.0); // (e¹ + e⁻¹) / 2
double tanh = Math.tanh(1.0); // sinh/cosh
// Logarithms
System.out.println(Math.log(Math.E)); // 1.0 (natural log: ln(e) = 1)
System.out.println(Math.log(1.0)); // 0.0
System.out.println(Math.log(0.0)); // -Infinity
System.out.println(Math.log(-1.0)); // NaN
System.out.println(Math.log10(1000.0)); // 3.0
System.out.println(Math.log10(1.0)); // 0.0
// log1p(x) — ln(1+x), accurate for tiny x where log(1+x) loses precision
double tiny = 1e-15;
double accurate = Math.log1p(tiny); // much more accurate than Math.log(1 + tiny)
// Change of base: log_b(x) = log(x) / log(b)
double log2of8 = Math.log(8) / Math.log(2); // 3.0
Math.random() returns a double in [0.0, 1.0). It is backed by a single global Random instance, which becomes a contention point in multi-threaded code. ThreadLocalRandom gives each thread its own generator with no contention and a richer API — it is the preferred choice for concurrent applications:
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
// Math.random() — double in [0.0, 1.0)
double rand = Math.random(); // e.g., 0.7342...
// Scale to a range [min, max)
double randomInRange = min + (max - min) * Math.random();
// Random integer in [0, n) — common pattern
int n = 10;
int randInt = (int) (Math.random() * n); // 0..9
// java.util.Random — more control, seedable
Random rng = new Random(); // non-deterministic seed
Random seeded = new Random(42L); // deterministic seed (for testing/reproducibility)
seeded.nextInt(); // any int
seeded.nextInt(100); // int in [0, 100)
seeded.nextLong(); // any long
seeded.nextDouble(); // double in [0.0, 1.0)
seeded.nextBoolean(); // true or false
seeded.nextGaussian(); // Gaussian-distributed double, mean 0, std 1
// Fill an array with random bytes
byte[] bytes = new byte[16];
rng.nextBytes(bytes);
// ThreadLocalRandom — preferred for concurrent code (no shared state, no contention)
int tRandInt = ThreadLocalRandom.current().nextInt(1, 101); // [1, 100]
double tRandD = ThreadLocalRandom.current().nextDouble(0.5, 1.5); // [0.5, 1.5)
long tRandL = ThreadLocalRandom.current().nextLong(1_000_000L); // [0, 1_000_000)
// Streams of random numbers (Java 8+)
ThreadLocalRandom.current()
.ints(5, 1, 7) // 5 random ints in [1, 7) (like dice rolls)
.forEach(System.out::println);
Random rng2 = new Random();
rng2.doubles(10, 0.0, 1.0) // stream of 10 doubles in [0.0, 1.0)
.average()
.ifPresent(System.out::println);
Math.random() and java.util.Random are not cryptographically secure — never use them for passwords, tokens, or security-sensitive values. Use java.security.SecureRandom for cryptographic purposes.
Integer arithmetic in Java silently wraps on overflow — Integer.MAX_VALUE + 1 gives Integer.MIN_VALUE with no exception. The Math.addExact(), subtractExact(), multiplyExact(), and toIntExact() methods throw ArithmeticException on overflow, making overflow bugs detectable rather than silent:
// Silent overflow — the default, dangerous for financial/safety-critical code
int max = Integer.MAX_VALUE; // 2_147_483_647
System.out.println(max + 1); // -2_147_483_648 (wraps silently!)
long lMax = Long.MAX_VALUE;
System.out.println(lMax + 1); // -9_223_372_036_854_775_808 (wraps silently!)
// Math.addExact / subtractExact / multiplyExact — throw on overflow
try {
int safe = Math.addExact(Integer.MAX_VALUE, 1); // throws ArithmeticException
} catch (ArithmeticException e) {
System.out.println("overflow detected: " + e.getMessage()); // "integer overflow"
}
int sum = Math.addExact(1_000_000, 2_000_000); // 3_000_000 — no overflow, fine
long lSum = Math.addExact(Long.MAX_VALUE - 1, 1L); // OK
int diff = Math.subtractExact(Integer.MIN_VALUE + 1, 1); // OK
// Math.subtractExact(Integer.MIN_VALUE, 1); // throws
long product = Math.multiplyExact(1_000_000L, 1_000_000L); // 1_000_000_000_000 — fine
// Math.multiplyExact(Long.MAX_VALUE, 2L); // throws
// toIntExact — safely cast long to int
long bigLong = 42L;
int asInt = Math.toIntExact(bigLong); // 42 — fine
// Math.toIntExact(Long.MAX_VALUE); // throws — doesn't fit in int
// negateExact — negate with overflow check
int negated = Math.negateExact(5); // -5
// Math.negateExact(Integer.MIN_VALUE); // throws (abs value doesn't fit)
// absExact (Java 15+) — abs with overflow check
int absVal = Math.absExact(-42); // 42
// Math.absExact(Integer.MIN_VALUE); // throws
// floorDiv / floorMod — division rounding toward -∞ (consistent sign of remainder)
// Standard % gives remainder with sign of dividend:
System.out.println( 7 % 3); // 1
System.out.println(-7 % 3); // -1 (may surprise you)
System.out.println( 7 % -3); // 1
System.out.println(-7 % -3); // -1
// floorMod always has the sign of the divisor:
System.out.println(Math.floorMod(-7, 3)); // 2 (not -1)
System.out.println(Math.floorMod( 7, -3)); // -2 (not 1)
// Practical: wrapping a circular buffer index
int index = -1;
int bufferSize = 8;
int wrapped = Math.floorMod(index, bufferSize); // 7 (not -1)
Use the exact methods (addExact, multiplyExact, etc.) whenever overflow would produce a silently wrong result — e.g., computing prices, timestamps, array indices, or population counts. Silent overflow is one of the most common sources of subtle numeric bugs in Java.