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
These are the most frequently used methods in java.lang.Math. Here is what each one does:
- abs(x) — absolute value. Returns the non-negative value of x. In other words, it strips the sign: abs(-5) → 5, abs(5) → 5. Useful whenever you care about magnitude, not direction — e.g. distance, error margin, difference between two values.
- min(a, b) — returns whichever of the two values is smaller.
- max(a, b) — returns whichever of the two values is larger.
- signum(x) — tells you the sign of a number without the magnitude: returns -1.0 if negative, 0.0 if zero, 1.0 if positive. Useful when you need to know direction but not how far.
- clamp(x, min, max) — (Java 21+) constrains a value to stay within a range. If x is below min it returns min; if above max it returns max; otherwise it returns x unchanged. A common need when capping user input, slider values, or scores.
All of these methods work with int, long, float, and double — Java picks the right version automatically based on the type you pass in.
// --- abs: absolute value ---
// Removes the sign — result is always >= 0
System.out.println(Math.abs(-42)); // 42
System.out.println(Math.abs(42)); // 42 (positive stays positive)
System.out.println(Math.abs(-3.14)); // 3.14
System.out.println(Math.abs(0)); // 0
// Practical use: how far apart are two temperatures?
double sensor1 = 98.6, sensor2 = 101.4;
double difference = Math.abs(sensor1 - sensor2); // 2.8 — order doesn't matter
// ⚠ Edge case: abs(Integer.MIN_VALUE) overflows — Java integers can't represent
// +2147483648, so the result wraps back to the same negative number.
System.out.println(Math.abs(Integer.MIN_VALUE)); // -2147483648 (not what you expect!)
// Use absExact() (Java 15+) to get an exception instead of a silent wrong answer:
// Math.absExact(Integer.MIN_VALUE); // throws ArithmeticException
// --- min and max: smaller / larger of two values ---
int smaller = Math.min(10, 20); // 10
long larger = Math.max(100L, 200L); // 200
double minD = Math.min(3.14, 2.71); // 2.71
// Practical use: enforce a maximum page size so callers can't request 10 million rows
int requestedSize = 5000;
int pageSize = Math.min(requestedSize, 100); // caps at 100
// --- clamp: keep a value inside a range ---
// Before Java 21, you had to nest min inside max (easy to get backwards):
int value = 150;
int clamped = Math.min(Math.max(value, 0), 100); // → 100 (clamped to [0, 100])
// Java 21+: Math.clamp() does the same thing more clearly
int result = Math.clamp(value, 0, 100); // 100 (150 exceeds max, so return max)
long lRes = Math.clamp(300L, 0L, 255L); // 255 (capped at max)
double dRes = Math.clamp(-1.5, 0.0, 1.0); // 0.0 (below min, so return min)
double mid = Math.clamp(0.5, 0.0, 1.0); // 0.5 (already in range, unchanged)
// --- signum: what direction is this number? ---
// Returns -1.0 (negative), 0.0 (zero), or 1.0 (positive)
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
// Practical use: apply consistent direction to a movement without caring about speed
double velocity = -7.5;
double direction = Math.signum(velocity); // -1.0 = moving left/down/backward
// copySign — take the magnitude of one number, apply the sign 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.