Pure Programmer
Blue Matrix


Cluster Map

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.

JavaScript Math Constants
Constant Description
Math.EEuler'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.

JavaScript Math Functions
Function Description
Math.abs(x)[[Absolute value]] of x
Math.acos(x)[[Arc cosine]] of x, result is in the range [0,π] [[Radians]]
Math.acosh(x)[[Arc hyperbolic cosine]] of x
Math.asin(x)[[Arc sine]] of x, result is in the range [-π/2,π/2] [[Radians]]
Math.asinh(x)[[Arc hyperbolic sine]] of x
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.atanh(x)[[Arc hyperbolic tangent]] of x
Math.ceil(x)Smallest integer value greater than or equal to x
Math.cos(x)[[Cosine]] of x (in [[Radians]])
Math.cosh(x)[[Hyperbolic cosine]] of x
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.sinh(x)[[Hyperbolic sine]] of x
Math.sqrt(x)[[Square root]] of x
Math.tan(x)[[Tangent]] of x (in [[Radians]])
Math.tanh(x)[[Hyperbolic tangent]] of x

The program below illustrates the use of the floating point math functions.

Math1.js
#!/usr/bin/env node;
/******************************************************************************
 * This program demonstrates the math library.
 * 
 * Copyright © 2016 Richard Lesh.  All rights reserved.
 *****************************************************************************/

const Utils = require('./Utils');

const main = async () => {
	const a = Math.PI / 6;
	const b = Math.PI / 4;
	const c = -a * 2;
	const d = -b * 2;
	const e = Math.E;

	console.log(Utils.format("pi = {0:f}", Math.PI));
	console.log(Utils.format("e = {0:f}", Math.E));

// abs, floor, ceil, round, trunc, min, max
	console.log(Utils.format("abs({0:f}) = {1:f}", a, Math.abs(a)));
	console.log(Utils.format("abs({0:f}) = {1:f}", c, Math.abs(c)));
	console.log(Utils.format("floor({0:f}) = {1:f}", a, Math.floor(a)));
	console.log(Utils.format("floor({0:f}) = {1:f}", c, Math.floor(c)));
	console.log(Utils.format("ceil({0:f}) = {1:f}", a, Math.ceil(a)));
	console.log(Utils.format("ceil({0:f}) = {1:f}", c, Math.ceil(c)));
	console.log(Utils.format("round({0:f}) = {1:f}", a, Math.round(a)));
	console.log(Utils.format("round({0:f}) = {1:f}", c, Math.round(c)));
	console.log(Utils.format("trunc({0:f}) = {1:f}", a, Math.trunc(a)));
	console.log(Utils.format("trunc({0:f}) = {1:f}", c, Math.trunc(c)));
	console.log(Utils.format("min({0:f}, {1:f}) = {2:f}", a, c, Math.min(a, c)));
	console.log(Utils.format("max({0:f}, {1:f}) = {2:f}", a, c, Math.max(a, c)));

// sin, cos, tan, atan, atan2, acos, asin
	console.log(Utils.format("sin({0:f}) = {1:f}", a, Math.sin(a)));
	console.log(Utils.format("sin({0:f}) = {1:f}", b, Math.sin(b)));
	console.log(Utils.format("sin({0:f}) = {1:f}", c, Math.sin(c)));
	console.log(Utils.format("sin({0:f}) = {1:f}", d, Math.sin(d)));
	console.log(Utils.format("cos({0:f}) = {1:f}", a, Math.cos(a)));
	console.log(Utils.format("cos({0:f}) = {1:f}", b, Math.cos(b)));
	console.log(Utils.format("cos({0:f}) = {1:f}", c, Math.cos(c)));
	console.log(Utils.format("cos({0:f}) = {1:f}", d, Math.cos(d)));
	console.log(Utils.format("tan({0:f}) = {1:f}", a, Math.tan(a)));
	console.log(Utils.format("tan({0:f}) = {1:f}", b, Math.tan(b)));
	console.log(Utils.format("tan({0:f}) = {1:f}", c, Math.tan(c)));
	console.log(Utils.format("asin({0:f}) = {1:f}", Math.sin(a), Math.asin(Math.sin(a))));
	console.log(Utils.format("asin({0:f}) = {1:f}", Math.sin(b), Math.asin(Math.sin(b))));
	console.log(Utils.format("asin({0:f}) = {1:f}", Math.sin(c), Math.asin(Math.sin(c))));
	console.log(Utils.format("asin({0:f}) = {1:f}", Math.sin(d), Math.asin(Math.sin(d))));
	console.log(Utils.format("acos({0:f}) = {1:f}", Math.cos(a), Math.acos(Math.cos(a))));
	console.log(Utils.format("acos({0:f}) = {1:f}", Math.cos(b), Math.acos(Math.cos(b))));
	console.log(Utils.format("acos({0:f}) = {1:f}", Math.cos(c), Math.acos(Math.cos(c))));
	console.log(Utils.format("acos({0:f}) = {1:f}", Math.cos(d), Math.acos(Math.cos(d))));
	console.log(Utils.format("atan({0:f}) = {1:f}", Math.tan(a), Math.atan(Math.tan(a))));
	console.log(Utils.format("atan({0:f}) = {1:f}", Math.tan(b), Math.atan(Math.tan(b))));
	console.log(Utils.format("atan({0:f}) = {1:f}", Math.tan(c), Math.atan(Math.tan(c))));
// 45 degrees
	console.log(Utils.format("atan2({0:f}, {1:f}) = {2:f}", 1.0, 1.0, Math.atan2(1.0, 1.0)));
// 30 degrees
	console.log(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
	console.log(Utils.format("sinh({0:f}) = {1:f}", a, Math.sinh(a)));
	console.log(Utils.format("sinh({0:f}) = {1:f}", b, Math.sinh(b)));
	console.log(Utils.format("sinh({0:f}) = {1:f}", c, Math.sinh(c)));
	console.log(Utils.format("sinh({0:f}) = {1:f}", d, Math.sinh(d)));
	console.log(Utils.format("cosh({0:f}) = {1:f}", a, Math.cosh(a)));
	console.log(Utils.format("cosh({0:f}) = {1:f}", b, Math.cosh(b)));
	console.log(Utils.format("cosh({0:f}) = {1:f}", c, Math.cosh(c)));
	console.log(Utils.format("cosh({0:f}) = {1:f}", d, Math.cosh(d)));
	console.log(Utils.format("tanh({0:f}) = {1:f}", a, Math.tanh(a)));
	console.log(Utils.format("tanh({0:f}) = {1:f}", b, Math.tanh(b)));
	console.log(Utils.format("tanh({0:f}) = {1:f}", c, Math.tanh(c)));
	console.log(Utils.format("tanh({0:f}) = {1:f}", d, Math.tanh(d)));
	console.log(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(a), Math.asinh(Math.sinh(a))));
	console.log(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(b), Math.asinh(Math.sinh(b))));
	console.log(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(c), Math.asinh(Math.sinh(c))));
	console.log(Utils.format("asinh({0:f}) = {1:f}", Math.sinh(d), Math.asinh(Math.sinh(d))));
	console.log(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(a), Math.acosh(Math.cosh(a))));
	console.log(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(b), Math.acosh(Math.cosh(b))));
	console.log(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(c), Math.acosh(Math.cosh(c))));
	console.log(Utils.format("acosh({0:f}) = {1:f}", Math.cosh(d), Math.acosh(Math.cosh(d))));
	console.log(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(a), Math.atanh(Math.tanh(a))));
	console.log(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(b), Math.atanh(Math.tanh(b))));
	console.log(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(c), Math.atanh(Math.tanh(c))));
	console.log(Utils.format("atanh({0:f}) = {1:f}", Math.tanh(d), Math.atanh(Math.tanh(d))));

// log, log10, exp, pow, sqrt
	console.log(Utils.format("log({0:f}) = {1:f}", a, Math.log(a)));
	console.log(Utils.format("log({0:f}) = {1:f}", b, Math.log(b)));
	console.log(Utils.format("log({0:f}) = {1:f}", -c, Math.log(-c)));
	console.log(Utils.format("log({0:f}) = {1:f}", -d, Math.log(-d)));
	console.log(Utils.format("log({0:f}) = {1:f}", e, Math.log(e)));
	console.log(Utils.format("log10({0:f}) = {1:f}", a, Math.log10(a)));
	console.log(Utils.format("log10({0:f}) = {1:f}", b, Math.log10(b)));
	console.log(Utils.format("log10({0:f}) = {1:f}", -c, Math.log10(-c)));
	console.log(Utils.format("log10({0:f}) = {1:f}", -d, Math.log10(-d)));
	console.log(Utils.format("log10({0:f}) = {1:f}", e, Math.log10(e)));
	console.log(Utils.format("exp({0:f}) = {1:f}", 0.5, Math.exp(0.5)));
	console.log(Utils.format("exp({0:f}) = {1:f}", 1.0, Math.exp(1.0)));
	console.log(Utils.format("exp({0:f}) = {1:f}", 2.0, Math.exp(2.0)));
	console.log(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 0.5, Math.pow(10.0, 0.5)));
	console.log(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 1.0, Math.pow(10.0, 1.0)));
	console.log(Utils.format("pow({0:f}, {1:f}) = {2:f}", 10.0, 2.0, Math.pow(10.0, 2.0)));
	console.log(Utils.format("sqrt({0:f}) = {1:f}", 0.5, Math.sqrt(0.5)));
	console.log(Utils.format("sqrt({0:f}) = {1:f}", 2.0, Math.sqrt(2.0)));
	console.log(Utils.format("sqrt({0:f}) = {1:f}", 10.0, Math.sqrt(10.0)));

// random numbers
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
}
main().catch( e => { console.error(e) } );

Output
$ node Math1.js pi = 3.141592653589793 e = 2.718281828459045 abs(0.5235987755982988) = 0.5235987755982988 abs(-1.0471975511965976) = 1.0471975511965976 floor(0.5235987755982988) = 0 floor(-1.0471975511965976) = -2 ceil(0.5235987755982988) = 1 ceil(-1.0471975511965976) = -1 round(0.5235987755982988) = 1 round(-1.0471975511965976) = -1 trunc(0.5235987755982988) = 0 trunc(-1.0471975511965976) = -1 min(0.5235987755982988, -1.0471975511965976) = -1.0471975511965976 max(0.5235987755982988, -1.0471975511965976) = 0.5235987755982988 sin(0.5235987755982988) = 0.49999999999999994 sin(0.7853981633974483) = 0.7071067811865475 sin(-1.0471975511965976) = -0.8660254037844386 sin(-1.5707963267948966) = -1 cos(0.5235987755982988) = 0.8660254037844387 cos(0.7853981633974483) = 0.7071067811865476 cos(-1.0471975511965976) = 0.5000000000000001 cos(-1.5707963267948966) = 6.123233995736766e-17 tan(0.5235987755982988) = 0.5773502691896257 tan(0.7853981633974483) = 0.9999999999999999 tan(-1.0471975511965976) = -1.7320508075688767 asin(0.49999999999999994) = 0.5235987755982988 asin(0.7071067811865475) = 0.7853981633974482 asin(-0.8660254037844386) = -1.0471975511965976 asin(-1) = -1.5707963267948966 acos(0.8660254037844387) = 0.5235987755982987 acos(0.7071067811865476) = 0.7853981633974483 acos(0.5000000000000001) = 1.0471975511965976 acos(6.123233995736766e-17) = 1.5707963267948966 atan(0.5773502691896257) = 0.5235987755982988 atan(0.9999999999999999) = 0.7853981633974483 atan(-1.7320508075688767) = -1.0471975511965976 atan2(1, 1) = 0.7853981633974483 atan2(1, 1.7320508075688772) = 0.5235987755982989 sinh(0.5235987755982988) = 0.5478534738880397 sinh(0.7853981633974483) = 0.8686709614860095 sinh(-1.0471975511965976) = -1.2493670505239751 sinh(-1.5707963267948966) = -2.3012989023072947 cosh(0.5235987755982988) = 1.1402383210764286 cosh(0.7853981633974483) = 1.3246090892520057 cosh(-1.0471975511965976) = 1.600286857702386 cosh(-1.5707963267948966) = 2.5091784786580567 tanh(0.5235987755982988) = 0.4804727781564516 tanh(0.7853981633974483) = 0.6557942026326724 tanh(-1.0471975511965976) = -0.7807144353592677 tanh(-1.5707963267948966) = -0.9171523356672744 asinh(0.5478534738880397) = 0.5235987755982988 asinh(0.8686709614860095) = 0.7853981633974482 asinh(-1.2493670505239751) = -1.0471975511965976 asinh(-2.3012989023072947) = -1.5707963267948966 acosh(1.1402383210764286) = 0.5235987755982986 acosh(1.3246090892520057) = 0.7853981633974482 acosh(1.600286857702386) = 1.0471975511965976 acosh(2.5091784786580567) = 1.5707963267948966 atanh(0.4804727781564516) = 0.5235987755982989 atanh(0.6557942026326724) = 0.7853981633974483 atanh(-0.7807144353592677) = -1.0471975511965976 atanh(-0.9171523356672744) = -1.570796326794897 log(0.5235987755982988) = -0.6470295833786549 log(0.7853981633974483) = -0.2415644752704905 log(1.0471975511965976) = 0.046117597181290375 log(1.5707963267948966) = 0.4515827052894548 log(2.718281828459045) = 1 log10(0.5235987755982988) = -0.2810013776895098 log10(0.7853981633974483) = -0.10491011863382856 log10(1.0471975511965976) = 0.02002861797447137 log10(1.5707963267948966) = 0.19611987703015263 log10(2.718281828459045) = 0.4342944819032518 exp(0.5) = 1.6487212707001282 exp(1) = 2.718281828459045 exp(2) = 7.38905609893065 pow(10, 0.5) = 3.1622776601683795 pow(10, 1) = 10 pow(10, 2) = 100 sqrt(0.5) = 0.7071067811865476 sqrt(2) = 1.4142135623730951 sqrt(10) = 3.1622776601683795 random() = 0.6589260751563037 random() = 0.12611978183819184 random() = 0.11624939234163323

The program below illustrates the use of the integer math and random number functions.

Math2.js
#!/usr/bin/env node;
/******************************************************************************
 * This program demonstrates the math integer functions.
 * 
 * Copyright © 2020 Richard Lesh.  All rights reserved.
 *****************************************************************************/

const Utils = require('./Utils');

const main = async () => {
	const a = 5;
	const b = 10;
	const c = -2;

// abs, floor, ceil, round, trunc, min, max
	console.log(Utils.format("abs({0:d}) = {1:d}", a, Math.abs(a)));
	console.log(Utils.format("abs({0:d}) = {1:d}", c, Math.abs(c)));
	console.log(Utils.format("min({0:d}, {1:d}) = {2:d}", a, b, Math.min(a, b)));
	console.log(Utils.format("max({0:d}, {1:d}) = {2:d}", a, b, Math.max(a, b)));
	console.log(Utils.format("min({0:d}, {1:d}) = {2:d}", b, c, Math.min(b, c)));
	console.log(Utils.format("max({0:d}, {1:d}) = {2:d}", b, c, Math.max(b, c)));

// random numbers
	console.log(Utils.format("random({0:d}) = {1:d}", a, Math.trunc(a * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", a, Math.trunc(a * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", a, Math.trunc(a * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", a, Math.trunc(a * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", a, Math.trunc(a * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", b, Math.trunc(b * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", b, Math.trunc(b * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", b, Math.trunc(b * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", b, Math.trunc(b * Math.random())));
	console.log(Utils.format("random({0:d}) = {1:d}", b, Math.trunc(b * Math.random())));
	console.log(Utils.format("random(2) = {0:d}", Math.trunc(2 * Math.random())));
	console.log(Utils.format("random(2) = {0:d}", Math.trunc(2 * Math.random())));
	console.log(Utils.format("random(2) = {0:d}", Math.trunc(2 * Math.random())));
	console.log(Utils.format("random(2) = {0:d}", Math.trunc(2 * Math.random())));
	console.log(Utils.format("random(2) = {0:d}", Math.trunc(2 * Math.random())));
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
	console.log(Utils.format("random() = {0:f}", Math.random()));
}
main().catch( e => { console.error(e) } );

Output
$ node Math2.js abs(5) = 5 abs(-2) = 2 min(5, 10) = 5 max(5, 10) = 10 min(10, -2) = -2 max(10, -2) = 10 random(5) = 4 random(5) = 1 random(5) = 2 random(5) = 1 random(5) = 2 random(10) = 4 random(10) = 5 random(10) = 0 random(10) = 9 random(10) = 1 random(2) = 0 random(2) = 0 random(2) = 1 random(2) = 1 random(2) = 1 random() = 0.14052396554971636 random() = 0.7230154864789451 random() = 0.33398566368614135 random() = 0.9815603605536798 random() = 0.06697961682649778

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 JavaScript, random number generation is usually done with the built-in Math.random() function.

For the three most common cases of uniform integers, uniform floating point numbers, and normally distributed ([[Gaussian]]) floating point numbers, JavaScript commonly uses:

  1. uniform integers → a helper based on Math.random()
  2. uniform floating point numbers → Math.random()
  3. normal (Gaussian) floating point numbers → a helper function such as the [[Box-Muller transform]]

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.

RandomNumbers.js
function randomInt(low, high) {
    return Math.floor(Math.random() * (high - low)) + low;
}

function randomGaussian() {
    let u1 = 0;
    let u2 = 0;

    // Avoid log(0)
    while (u1 === 0) {
        u1 = Math.random();
    }
    while (u2 === 0) {
        u2 = Math.random();
    }

    return Math.sqrt(-2.0 * Math.log(u1)) * Math.cos(2.0 * Math.PI * u2);
}

console.log("Uniform integers in [1, 6]");
for (let i = 0; i < 10; ++i) {
    console.log(randomInt(1, 7));
}

console.log("Uniform numbers in [0.0, 1.0)");
for (let i = 0; i < 10; ++i) {
    console.log(Math.random());
}

console.log("Standard Normal");
for (let i = 0; i < 10; ++i) {
    console.log(randomGaussian());
}
Output
$ node RandomNumbers.js Uniform integers in [1, 6] 1 1 4 1 6 6 5 4 6 1 Uniform numbers in [0.0, 1.0) 0.31217642303337056 0.27998769911493115 0.09027375250962644 0.3447791379625358 0.900125820746089 0.06357069985031094 0.9267088300916779 0.23394975374457072 0.20231937108419418 0.1871248668912533 Standard Normal 0.23342482409317383 1.1224248500096343 -0.3763052665346438 0.0063113431958218245 0.805116293469488 -1.606938719785736 0.0710752988342298 -1.405533498579826 0.731571117278217 0.4553584563109022

The uniform integer generator can produce integers uniformly in a range such as: [1, 6].

In JavaScript, a common way to simulate a six-sided die is: Math.floor(Math.random() * 6) + 1.

This works by first generating a floating point number in the interval [0.0, 1.0), scaling it to [0.0, 6.0), taking the floor to get one of 0 through 5, and then adding 1 to shift the range to 1 through 6.

That makes it perfect for dice rolls, random indices, and similar cases.

The uniform floating point generator produces numbers 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) * Math.random().

That is commonly used for probabilities, simulation, [[Monte Carlo Method]], and scaling into another range.

JavaScript does not provide a built-in Gaussian random number generator. To generate values from a normal distribution with mean = 0.0 and standard deviation = 1.0, we usually write a helper function based on the [[Box-Muller transform]].

That produces values from 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 * randomGaussian().

Deterministic vs Non-Deterministic Seeding

Unlike Java, standard JavaScript does not provide a built-in way to set the seed for Math.random().

That means Math.random() is convenient for general-purpose use, but it is not ideal when you need repeatable sequences for debugging, testing, or scientific simulations.

If you want deterministic pseudorandom numbers in JavaScript, you usually write or import a seeded generator function instead of relying on Math.random().

Whichever technique you choose, create the generator once and reuse it rather than recreating it repeatedly in a loop.

Cryptographically Secure Random Numbers

For security-sensitive work such as tokens, keys, or passwords, do not use Math.random().

In browsers, use the Web Crypto API instead: crypto.getRandomValues().

const values = new Uint32Array(1);
crypto.getRandomValues(values);
console.log(values[0]);

This produces much higher quality random values for security-related purposes.

Why use helper functions?

JavaScript’s built-in random support is simple, but it is limited because:

For quick one-line examples, Math.random() is fine. But for simulations, games, testing, or reusable code, helper functions or a dedicated random-number library are often the better tool.

Questions

Projects

More ★'s indicate higher difficulty level.

References