Math Library
While the arithmetic and logic operators represent the basic operations that our [[CPU]] can perform, there are many other common math functions that com in handy. Since they are so common, programming languages usually have a math library that provides these functions. Logarithms, trigonometry and random number generation are just of few of the types of functions typically provided.
Math Constants
Math constants provide commonly used mathematical constanst to the highest precesion available. Some of the more useful math constants are summarized below.
| Constant | Description |
|---|---|
| Math.E | Euler's constant [[ℯ]], base of the natural logarithm |
| Math.PI | [[π]], Ratio of a circle's circumference to its diameter |
Math Functions
These most useful math functions are summarized below.
| Function | Description |
|---|---|
| Math.abs(x) | [[Absolute value]] of x |
| Math.acos(x) | [[Arc cosine]] of x, result is in the range [0,π] [[Radians]] |
| Math.asin(x) | [[Arc sine]] of x, result is in the range [-π/2,π/2] [[Radians]] |
| Math.atan(x) | [[Arc tangent]] of x, result is in the range [-π/2,π/2] [[Radians]] |
| Math.atan2(y,x) | Angle θ from the conversion of [[rectangular coordinates]] (x,y), result is in the range [-π,π] [[Radians]] |
| Math.ceil(x) | Smallest integer value greater than or equal to x |
| Math.cos(x) | [[Cosine]] of x (in [[Radians]]) |
| Math.exp(x) | [[ℯ]] rasied to the power x, i.e. ℯx |
| Math.floor(x) | Largest integer less than or equal to x |
| Math.log(x) | [[Natural logarithm]] of x |
| Math.log10(x) | [[Common logarithm]] of x |
| Math.max(x,y) | Larger of x and y |
| Math.min(x,y) | Smaller of x and y |
| Math.pow(x,y) | x raised to the power y, i.e. xy |
| Math.random() | [[Pseudorandom]] number on the interval [0,1) |
| Math.round(x) | Nearest integer to x |
| Math.sin(x) | [[Sine]] of x (in [[Radians]]) |
| Math.sqrt(x) | [[Square root]] of x |
| Math.tan(x) | [[Tangent]] of x (in [[Radians]]) |
You can add the following import to the top of your program in order to use these math functions and constants without the Math package name.
import static java.lang.Math.*;
The program below illustrates the use of the floating point math functions.
/******************************************************************************
* This program demonstrates the math library.
*
* Copyright © 2016 Richard Lesh. All rights reserved.
*****************************************************************************/
import org.pureprogrammer.Utils;
public class Math1 {
public static void main(String[] args) {
final double a = Math.PI / 6;
final double b = Math.PI / 4;
final double c = -a * 2;
final double d = -b * 2;
final double e = Math.E;
System.out.println(Utils.format("pi = {0:f}", Math.PI));
System.out.println(Utils.format("e = {0:f}", Math.E));
// abs, floor, ceil, round, trunc, min, max
System.out.println(Utils.format("abs({0:f}) = {1:f}", a, Math.abs(a)));
System.out.println(Utils.format("abs({0:f}) = {1:f}", c, Math.abs(c)));
System.out.println(Utils.format("floor({0:f}) = {1:f}", a, Math.floor(a)));
System.out.println(Utils.format("floor({0:f}) = {1:f}", c, Math.floor(c)));
System.out.println(Utils.format("ceil({0:f}) = {1:f}", a, Math.ceil(a)));
System.out.println(Utils.format("ceil({0:f}) = {1:f}", c, Math.ceil(c)));
System.out.println(Utils.format("round({0:f}) = {1:f}", a, Math.round(a)));
System.out.println(Utils.format("round({0:f}) = {1:f}", c, Math.round(c)));
System.out.println(Utils.format("trunc({0:f}) = {1:f}", a, a < 0.0 ? Math.ceil(a) : Math.floor(a)));
System.out.println(Utils.format("trunc({0:f}) = {1:f}", c, c < 0.0 ? Math.ceil(c) : Math.floor(c)));
System.out.println(Utils.format("min({0:f}, {1:f}) = {2:f}", a, c, Math.min(a, c)));
System.out.println(Utils.format("max({0:f}, {1:f}) = {2:f}", a, c, Math.max(a, c)));
// sin, cos, tan, atan, atan2, acos, asin
System.out.println(Utils.format("sin({0:f}) = {1:f}", a, Math.sin(a)));
System.out.println(Utils.format("sin({0:f}) = {1:f}", b, Math.sin(b)));
System.out.println(Utils.format("sin({0:f}) = {1:f}", c, Math.sin(c)));
System.out.println(Utils.format("sin({0:f}) = {1:f}", d, Math.sin(d)));
System.out.println(Utils.format("cos({0:f}) = {1:f}", a, Math.cos(a)));
System.out.println(Utils.format("cos({0:f}) = {1:f}", b, Math.cos(b)));
System.out.println(Utils.format("cos({0:f}) = {1:f}", c, Math.cos(c)));
System.out.println(Utils.format("cos({0:f}) = {1:f}", d, Math.cos(d)));
System.out.println(Utils.format("tan({0:f}) = {1:f}", a, Math.tan(a)));
System.out.println(Utils.format("tan({0:f}) = {1:f}", b, Math.tan(b)));
System.out.println(Utils.format("tan({0:f}) = {1:f}", c, Math.tan(c)));
System.out.println(Utils.format("asin({0:f}) = {1:f}", Math.sin(a), Math.asin(Math.sin(a))));
System.out.println(Utils.format("asin({0:f}) = {1:f}", Math.sin(b), Math.asin(Math.sin(b))));
System.out.println(Utils.format("asin({0:f}) = {1:f}", Math.sin(c), Math.asin(Math.sin(c))));
System.out.println(Utils.format("asin({0:f}) = {1:f}", Math.sin(d), Math.asin(Math.sin(d))));
System.out.println(Utils.format("acos({0:f}) = {1:f}", Math.cos(a), Math.acos(Math.cos(a))));
System.out.println(Utils.format("acos({0:f}) = {1:f}", Math.cos(b), Math.acos(Math.cos(b))));
System.out.println(Utils.format("acos({0:f}) = {1:f}", Math.cos(c), Math.acos(Math.cos(c))));
System.out.println(Utils.format("acos({0:f}) = {1:f}", Math.cos(d), Math.acos(Math.cos(d))));
System.out.println(Utils.format("atan({0:f}) = {1:f}", Math.tan(a), Math.atan(Math.tan(a))));
System.out.println(Utils.format("atan({0:f}) = {1:f}", Math.tan(b), Math.atan(Math.tan(b))));
System.out.println(Utils.format("atan({0:f}) = {1:f}", Math.tan(c), Math.atan(Math.tan(c))));
// 45 degrees
System.out.println(Utils.format("atan2({0:f}, {1:f}) = {2:f}", 1.0, 1.0, Math.atan2(1.0, 1.0)));
// 30 degrees
System.out.println(Utils.format("atan2({0:f}, {1:f}) = {2:f}", 1.0, Math.sqrt(3.0), Math.atan2(1.0, Math.sqrt(3.0))));
// sinh, cosh, tanh, atanh, acosh, asinh
System.out.println(Utils.format("sinh({0:f}) = {1:f}", a, Math.sinh(a)));
System.out.println(Utils.format("sinh({0:f}) = {1:f}", b, Math.sinh(b)));
System.out.println(Utils.format("sinh({0:f}) = {1:f}", c, Math.sinh(c)));
System.out.println(Utils.format("sinh({0:f}) = {1:f}", d, Math.sinh(d)));
System.out.println(Utils.format("cosh({0:f}) = {1:f}", a, Math.cosh(a)));
System.out.println(Utils.format("cosh({0:f}) = {1:f}", b, Math.cosh(b)));
System.out.println(Utils.format("cosh({0:f}) = {1:f}", c, Math.cosh(c)));
System.out.println(Utils.format("cosh({0:f}) = {1:f}", d, Math.cosh(d)));
System.out.println(Utils.format("tanh({0:f}) = {1:f}", a, Math.tanh(a)));
System.out.println(Utils.format("tanh({0:f}) = {1:f}", b, Math.tanh(b)));
System.out.println(Utils.format("tanh({0:f}) = {1:f}", c, Math.tanh(c)));
System.out.println(Utils.format("tanh({0:f}) = {1:f}", d, Math.tanh(d)));
System.out.println(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(a), Math.log(Math.sinh(a) + Math.sqrt(Math.sinh(a) * Math.sinh(a) + 1.0))));
System.out.println(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(b), Math.log(Math.sinh(b) + Math.sqrt(Math.sinh(b) * Math.sinh(b) + 1.0))));
System.out.println(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(c), Math.log(Math.sinh(c) + Math.sqrt(Math.sinh(c) * Math.sinh(c) + 1.0))));
System.out.println(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(d), Math.log(Math.sinh(d) + Math.sqrt(Math.sinh(d) * Math.sinh(d) + 1.0))));
System.out.println(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(a), Math.log(Math.cosh(a) + Math.sqrt(Math.cosh(a) * Math.cosh(a) - 1.0))));
System.out.println(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(b), Math.log(Math.cosh(b) + Math.sqrt(Math.cosh(b) * Math.cosh(b) - 1.0))));
System.out.println(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(c), Math.log(Math.cosh(c) + Math.sqrt(Math.cosh(c) * Math.cosh(c) - 1.0))));
System.out.println(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(d), Math.log(Math.cosh(d) + Math.sqrt(Math.cosh(d) * Math.cosh(d) - 1.0))));
System.out.println(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(a), 0.5 * Math.log((1.0 + Math.tanh(a))/(1.0 - Math.tanh(a)))));
System.out.println(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(b), 0.5 * Math.log((1.0 + Math.tanh(b))/(1.0 - Math.tanh(b)))));
System.out.println(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(c), 0.5 * Math.log((1.0 + Math.tanh(c))/(1.0 - Math.tanh(c)))));
System.out.println(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(d), 0.5 * Math.log((1.0 + Math.tanh(d))/(1.0 - Math.tanh(d)))));
// log, log10, exp, pow, sqrt
System.out.println(Utils.format("log({0:f}) = {1:f}", a, Math.log(a)));
System.out.println(Utils.format("log({0:f}) = {1:f}", b, Math.log(b)));
System.out.println(Utils.format("log({0:f}) = {1:f}", -c, Math.log(-c)));
System.out.println(Utils.format("log({0:f}) = {1:f}", -d, Math.log(-d)));
System.out.println(Utils.format("log({0:f}) = {1:f}", e, Math.log(e)));
System.out.println(Utils.format("log10({0:f}) = {1:f}", a, Math.log10(a)));
System.out.println(Utils.format("log10({0:f}) = {1:f}", b, Math.log10(b)));
System.out.println(Utils.format("log10({0:f}) = {1:f}", -c, Math.log10(-c)));
System.out.println(Utils.format("log10({0:f}) = {1:f}", -d, Math.log10(-d)));
System.out.println(Utils.format("log10({0:f}) = {1:f}", e, Math.log10(e)));
System.out.println(Utils.format("exp({0:f}) = {1:f}", 0.5, Math.exp(0.5)));
System.out.println(Utils.format("exp({0:f}) = {1:f}", 1.0, Math.exp(1.0)));
System.out.println(Utils.format("exp({0:f}) = {1:f}", 2.0, Math.exp(2.0)));
System.out.println(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 0.5, Math.pow(10.0, 0.5)));
System.out.println(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 1.0, Math.pow(10.0, 1.0)));
System.out.println(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 2.0, Math.pow(10.0, 2.0)));
System.out.println(Utils.format("sqrt({0:f}) = {1:f}", 0.5, Math.sqrt(0.5)));
System.out.println(Utils.format("sqrt({0:f}) = {1:f}", 2.0, Math.sqrt(2.0)));
System.out.println(Utils.format("sqrt({0:f}) = {1:f}", 10.0, Math.sqrt(10.0)));
// random numbers
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
}
}
Output
The program below illustrates the use of the integer math and random number functions.
/******************************************************************************
* This program demonstrates the math integer functions.
*
* Copyright © 2020 Richard Lesh. All rights reserved.
*****************************************************************************/
import org.pureprogrammer.Utils;
public class Math2 {
public static void main(String[] args) {
final int a = 5;
final int b = 10;
final int c = -2;
// abs, floor, ceil, round, trunc, min, max
System.out.println(Utils.format("abs({0:d}) = {1:d}", a, Math.abs(a)));
System.out.println(Utils.format("abs({0:d}) = {1:d}", c, Math.abs(c)));
System.out.println(Utils.format("min({0:d}, {1:d}) = {2:d}", a, b, Math.min(a, b)));
System.out.println(Utils.format("max({0:d}, {1:d}) = {2:d}", a, b, Math.max(a, b)));
System.out.println(Utils.format("min({0:d}, {1:d}) = {2:d}", b, c, Math.min(b, c)));
System.out.println(Utils.format("max({0:d}, {1:d}) = {2:d}", b, c, Math.max(b, c)));
// random numbers
System.out.println(Utils.format("random({0:d}) = {1:d}", a, (int)(a * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", a, (int)(a * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", a, (int)(a * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", a, (int)(a * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", a, (int)(a * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", b, (int)(b * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", b, (int)(b * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", b, (int)(b * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", b, (int)(b * Math.random())));
System.out.println(Utils.format("random({0:d}) = {1:d}", b, (int)(b * Math.random())));
System.out.println(Utils.format("random(2) = {0:d}", (int)(2 * Math.random())));
System.out.println(Utils.format("random(2) = {0:d}", (int)(2 * Math.random())));
System.out.println(Utils.format("random(2) = {0:d}", (int)(2 * Math.random())));
System.out.println(Utils.format("random(2) = {0:d}", (int)(2 * Math.random())));
System.out.println(Utils.format("random(2) = {0:d}", (int)(2 * Math.random())));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
System.out.println(Utils.format("random() = {0:f}", Math.random()));
}
}
Output
Random Numbers
Random number generation is an important technique needed for simulations and games. Computers can't actually generate true random numbers, so we have to settle for [[pseudorandom]] numbers, i.e. numbers generated deterministically but hopefully in an unpredictable manner.
In modern Java, random number generation is usually done with classes from the standard library such as java.util.Random, java.util.concurrent.ThreadLocalRandom, and the newer java.util.random interfaces and generators.
For the three most common cases of uniform integers, uniform floating point numbers, and normally distributed ([[Gaussian]]) floating point numbers, Java provides methods such as:
- uniform integers →
nextInt()ornextInt(origin, bound) - uniform floats/doubles →
nextDouble() - normal (Gaussian) floats/doubles →
nextGaussian()
For our example program we generate 10 numbers from each of the three distributions. Notice how each time we run the program, we will usually get different values.
import java.util.Random;
public class RandomNumbers {
public static void main(String[] args) {
Random rng = new Random();
System.out.println("Uniform integers in [1, 6]");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextInt(6) + 1);
}
System.out.println("Uniform doubles in [0.0, 1.0)");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextDouble());
}
System.out.println("Standard Normal");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextGaussian());
}
}
}
Output
The uniform integer generator can produce integers uniformly in a range such as: [1, 6].
In Java, integer bounds are usually expressed with an inclusive lower bound and an exclusive upper bound. So to simulate a six-sided die we would write:
rng.nextInt(1, 7).
This means that 1 is included and 7 is excluded, so the possible values are 1 through 6. That makes it perfect for dice rolls, random indices in a half-open range, and similar cases.
The uniform floating point generator produces doubles uniformly in the range: [0.0, 1.0).
This means that only the low endpoint 0.0 is included. The high endpoint 1.0 will not be generated, i.e. low <= random < high. You can scale this output to another range [low, high) with the formula low + (high - low) * rng.nextDouble()
That is commonly used for probabilities, simulation, [[Monte Carlo Method]], and scaling into another range.
The Gaussian generator produces values from a normal distribution with mean = 0.0 and standard deviation = 1.0. That is called the standard normal distribution.
Most values cluster near the mean, and larger positive or negative values become less likely.
For example, to model exam scores centered around 75 with a standard deviation of 10, we can scale and shift the standard normal value like this:
75.0 + 10.0 * rng.nextGaussian().
Example Java Program
import java.util.Random;
public class RandomNumbers {
public static void main(String[] args) {
Random rng = new Random();
System.out.println("Uniform integers in [1, 6]");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextInt(6) + 1);
}
System.out.println("Uniform doubles in [0.0, 1.0)");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextDouble());
}
System.out.println("Standard Normal");
for (int i = 0; i < 10; ++i) {
System.out.println(rng.nextGaussian());
}
}
}
Deterministic vs Non-Deterministic Seeding
If you want the same random sequence every run, use a fixed seed such as 12345. This is useful for debugging and testing.
Random rng = new Random(12345);
If you want variation between runs, use the default constructor:
new Random().
This seeds the generator automatically using a random seed.
Whichever technique you choose, only seed the generator once. Do not recreate and re-seed it repeatedly in a loop.
ThreadLocalRandom
In multithreaded Java programs, ThreadLocalRandom is often preferred because it avoids contention between threads.
import java.util.concurrent.ThreadLocalRandom; int dieRoll = ThreadLocalRandom.current().nextInt(1, 7); double x = ThreadLocalRandom.current().nextDouble();
Newer Java Random Generators
Newer versions of Java also provide the java.util.random package, which offers a more flexible random number framework with interfaces such as RandomGenerator.
import java.util.random.RandomGenerator; RandomGenerator rng = RandomGenerator.getDefault(); int dieRoll = rng.nextInt(1, 7); double x = rng.nextDouble(10., 20.); // low bound, high bound (exclusive) double g = rng.nextGaussian(70., 10.); // mean, std. dev.
Why not use Math.random()?
Older Java code often uses: Math.random()
This is acceptable for simple cases, but it is more limited because:
- it only directly produces doubles
- it is awkward for integer ranges
- it does not directly support Gaussian values
- it is less flexible than using an explicit random generator object
For quick one-line examples, Math.random() is fine. But for serious simulation, games, testing, or reusable code, Random, ThreadLocalRandom, or RandomGenerator is usually the better tool.
Questions
- {{Write an expression that yields √5.}}
- {{Write an expression that yields 3√5.}}
- {{Write an expression that yields the secant of π/4.}}
- {{Write an expression that yields log16 100.}}
Projects
More ★'s indicate higher difficulty level.
References
- [[Java Language Specification]], Java SE 21 Edition, Gosling, et. al., 2023.
- [[Java Tutorials]]
- [[Java at TutorialsPoint]]
- Download Java at [[Amazon Corretto]], [[Azul Zulu]], [[Eclipse Temurin]] or [[Oracle JDK]]
Pure Programmer


