Java Math Class: Methods, Rounding, and Safe Arithmetic
java.lang.Math is a utility class of static methods covering the most common numeric operations: absolute value, min/max, power, square root, rounding, trigonometry, logarithms, and random number generation. Every method is static: no instantiation needed. For concurrent applications, ThreadLocalRandom outperforms Math.random(). For code that must not silently overflow, the exact methods (addExact, multiplyExact) throw ArithmeticException instead of wrapping around.
Contents
Basic Operations: abs, min, max, signum, clamp
These are the most frequently used methods in java.lang.Math
- abs(x): absolute value. Returns the non-negative value of
. In other words, it strips the sign:x โabs(-5) ,5 โabs(5) . Useful whenever you care about magnitude, not direction: e.g. distance, error margin, difference between two values.5 - 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
if negative,-1.0 if zero,0.0 if positive. Useful when you need to know direction but not how far.1.0 - clamp(x, min, max): (Java 21+) constrains a value to stay within a range. If
is belowx it returnsmin ; if abovemin it returnsmax ; otherwise it returnsmax unchanged. A common need when capping user input, slider values, or scores.x
All of these methods work with intlongfloatdouble
// --- 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
Power and Roots: pow, sqrt, cbrt, hypot
Math.pow(base, exp)doubleMath.sqrt()Math.cbrt()Math.hypot(x, y)
// 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)
Rounding: floor, ceil, round, rint
Java provides four rounding functions with distinct semantics: floorceilroundrint
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)
Math.floorMod()%%Trigonometry, Logarithms, and Constants
All trigonometric functions in MathMath.toRadians()Math.toDegrees()Math.log()Math.log10()Math.log1p()
// 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
Random Numbers: Math.random() and ThreadLocalRandom
Math.random()doubleRandomThreadLocalRandom
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()java.util.Randomjava.security.SecureRandomOverflow-Safe Arithmetic: exact Methods and floorDiv
Integer arithmetic in Java silently wraps on overflow: Integer.MAX_VALUE + 1Integer.MIN_VALUEMath.addExact()subtractExact()multiplyExact()toIntExact()ArithmeticException
// 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)
exactaddExactmultiplyExact