Math Class
java.lang.Math is a utility class of static methods for numeric operations: absolute values, minimum and maximum, rounding, powers and roots, logarithms, trigonometry, overflow-checked arithmetic, and floor-based division. It cannot be instantiated, and it is in java.lang, so it needs no import. The earlier Java Math lesson introduced the most common methods; this lesson organizes the whole class by purpose and covers the methods that solve specific, recurring problems in real code.
Constants
Math.PI // 3.141592653589793
Math.E // 2.718281828459045
Math.TAU // 6.283185307179586 (2π, Java 19+)
Basic Operations
| Method | Purpose | Example | Result |
|---|---|---|---|
abs(x) | Absolute value | Math.abs(-4.5) | 4.5 |
max(a, b), min(a, b) | Larger / smaller | Math.max(3, 8) | 8 |
clamp(v, min, max) | Restrict to a range (Java 21) | Math.clamp(150, 0, 100) | 100 |
signum(x) | −1.0, 0.0, or 1.0 | Math.signum(-4.2) | -1.0 |
copySign(mag, sign) | Magnitude of one value with the sign of another | Math.copySign(3.0, -1.0) | -3.0 |
Most methods are overloaded for int, long, float, and double; the result type matches the arguments.
Two edge cases:
Math.abs(Integer.MIN_VALUE); // -2147483648: its positive value does not fit in an int
Math.min(Double.NaN, 1.0); // NaN: any NaN argument produces NaN
Math.absExact (Java 15) throws instead of returning a negative absolute value.
Rounding
| Method | Returns | 2.5 | -2.5 | 2.4 |
|---|---|---|---|---|
Math.round(x) | long (or int for float) | 3 | -2 | 2 |
Math.rint(x) | double, halves to even | 2.0 | -2.0 | 2.0 |
Math.floor(x) | double, toward −∞ | 2.0 | -3.0 | 2.0 |
Math.ceil(x) | double, toward +∞ | 3.0 | -2.0 | 3.0 |
For rounding money to decimal places, use BigDecimal.setScale rather than any of these.
Powers, Roots, and Logarithms
| Method | Computes | Example | Result |
|---|---|---|---|
pow(a, b) | aᵇ | Math.pow(2, 10) | 1024.0 |
sqrt(x) | √x | Math.sqrt(144) | 12.0 |
cbrt(x) | ∛x | Math.cbrt(27) | 3.0 |
hypot(x, y) | √(x² + y²) without overflow | Math.hypot(3, 4) | 5.0 |
exp(x) | eˣ | Math.exp(1) | 2.718... |
log(x) | Natural log | Math.log(Math.E) | 1.0 |
log10(x) | Base-10 log | Math.log10(1000) | 3.0 |
log1p(x), expm1(x) | ln(1 + x), eˣ − 1, accurate for tiny x | Math.log1p(1e-10) | 9.9999999995E-11 |
fma(a, b, c) | a × b + c with a single rounding | Math.fma(2.0, 3.0, 1.0) | 7.0 |
All of these return double. sqrt of a negative number and log of a non-positive number return NaN or -Infinity rather than throwing.
log1p and expm1 exist because computing Math.log(1 + x) for very small x loses most of its precision when 1 + x rounds to almost exactly 1. Financial and scientific code uses them for small interest rates and growth factors.
Trigonometry
sin, cos, tan, asin, acos, atan, atan2, and the hyperbolic functions all work in radians. Convert with toRadians and toDegrees:
Math.sin(Math.toRadians(30)); // 0.49999999999999994
Math.toDegrees(Math.atan2(1, 1)); // 45.0
Math.sin(Math.PI); // 1.2246467991473532E-16, not exactly 0
atan2(y, x) returns the angle of the point (x, y), correctly handling all four quadrants, which atan(y / x) cannot.
Overflow-Checked Arithmetic
Ordinary int and long arithmetic wraps around silently on overflow. The Exact methods throw ArithmeticException instead:
| Method | Checks |
|---|---|
addExact, subtractExact, multiplyExact | Result fits in int / long |
incrementExact, decrementExact, negateExact | Result fits |
toIntExact(long) | The long fits in an int |
absExact | Absolute value fits (Java 15) |
Math.addExact(Integer.MAX_VALUE, 1); // ArithmeticException: integer overflow
Math.toIntExact(3_000_000_000L); // ArithmeticException: integer overflow
Use them wherever a wrapped-around value would be dangerous: quantities, balances, buffer sizes, or array lengths computed from input.
Floor Division and Modulus
Java's / and % round toward zero, so with negative operands the remainder is negative. floorDiv and floorMod round toward negative infinity, so floorMod always returns a result with the sign of the divisor:
-7 / 2; // -3
Math.floorDiv(-7, 2); // -4
-7 % 3; // -1
Math.floorMod(-7, 3); // 2
Math.ceilDiv(47, 10); // 5 (Java 18): division rounded up
floorMod is the correct tool for wrapping a possibly negative value into a range: days of the week, positions in a circular buffer, rotation angles, or clock hours. ceilDiv answers "how many groups are needed": pages of results, boxes for items, or servers for users.
Floating-Point Inspection
| Method | Returns |
|---|---|
ulp(x) | The gap between x and the next representable value |
nextUp(x), nextDown(x) | The adjacent representable values |
getExponent(x) | The unbiased binary exponent |
scalb(x, n) | x × 2ⁿ |
These are used when writing numeric algorithms and choosing comparison tolerances.
Random Numbers
Math.random() returns a double in [0.0, 1.0). For anything beyond a quick experiment, the Random family of classes is more convenient and more flexible; it is covered in the next lesson.
StrictMath
java.lang.StrictMath has the same methods as Math but guarantees bit-for-bit identical results on every platform. Math may use faster CPU-specific implementations for some functions, whose last bit can differ between machines. Use StrictMath only when exact reproducibility across platforms is a requirement, such as in certain simulations or cross-platform test suites.
Practical Example: Dashboard Helpers
A learning dashboard needs several small calculations: scheduling by weekday, displaying watch time, pagination, progress bars, and percentage changes, all with correct behavior at the edges.
public class Dashboard {
static final String[] DAYS = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
static String dayAfter(int startIndex, int offset) {
return DAYS[Math.floorMod(startIndex + offset, 7)];
}
static String duration(long totalSeconds) {
return String.format("%d:%02d:%02d", totalSeconds / 3600, totalSeconds % 3600 / 60, totalSeconds % 60);
}
static String progressBar(double done, double total, int width) {
double ratio = Math.clamp(done / total, 0.0, 1.0);
int filled = (int) Math.round(ratio * width);
return "[" + "#".repeat(filled) + "-".repeat(width - filled) + "] " + Math.round(ratio * 100) + "%";
}
static double percentChange(double before, double after) {
return (after - before) / Math.abs(before) * 100;
}
public static void main(String[] args) {
System.out.println("10 days after Wed: " + dayAfter(2, 10));
System.out.println("3 days before Mon: " + dayAfter(0, -3));
System.out.println("Watch time: " + duration(3725));
System.out.println("Pages needed: " + Math.ceilDiv(47, 10));
System.out.println(progressBar(7, 12, 20));
System.out.println(progressBar(15, 12, 20));
System.out.printf("Revenue change: %+.1f%%%n", percentChange(1250, 1475));
System.out.printf("Loss change: %+.1f%%%n", percentChange(-200, -150));
try {
int seats = Math.multiplyExact(60_000, 40_000);
} catch (ArithmeticException e) {
System.out.println("Seat calculation failed: " + e.getMessage());
}
}
}
Output (Java 21 or later, for Math.clamp):
10 days after Wed: Sat
3 days before Mon: Fri
Watch time: 1:02:05
Pages needed: 5
[############--------] 58%
[####################] 100%
Revenue change: +18.0%
Loss change: +25.0%
Seat calculation failed: integer overflow
Each helper relies on a specific Math method for correctness at the edges:
dayAfterusesfloorMod, so negative offsets wrap correctly: 3 days before Monday is Friday, where%would have produced an invalid negative index.durationuses integer division and remainder to split seconds into hours, minutes, and seconds.ceilDivgives 5 pages for 47 items at 10 per page, where plain division would give 4.progressBarusesclampso an over-complete value (15 of 12) shows a full bar instead of a negative count of dashes, androundto convert the ratio to a whole number of characters.percentChangedivides byMath.abs(before)so an improvement from a loss of 200 to a loss of 150 is reported as a positive change.multiplyExactreports that 60,000 × 40,000 exceedsintrange instead of silently producing a negative seat count.