Math - Learning JavaScript (2016)

Learning JavaScript (2016)

Chapter 16. Math

This chapter describes JavaScript’s built-in Math object, which contains math functions commonly encountered in application development (if you are doing sophisticated numeric analysis, you may have to find third-party libraries).

Before we delve into the library, let’s remind ourselves how JavaScript handles numbers. In particular, there’s no dedicated integer class; all numbers are IEEE 754 64-bit floating-point numbers. For most functions in the math library, this simplifies things: a number is a number. While no computer will ever be able to fully represent an arbitrary real number, for practical purposes, you can think of JavaScript numbers as real numbers. Note that there’s no built-in support for complex numbers in JavaScript. If you need complex numbers, bignums, or more sophisticated structures or algorithms, I recommend starting with Math.js.

Outside of some basics, this chapter is not designed to teach you math; that’s a book (or 2 or 10) of its own.

Throughout the code comments in this chapter, I will use a tilde (~) prefix to indicate that a given value is approximate. I will also refer to properties of the Math object as functions, not methods. While they are technically static methods, the distinction is academic here, as the Math object provides namespacing, not context.

Formatting Numbers

A common need is to format numbers; that is, instead of displaying 2.0093, you want to display 2.1. Or instead of displaying 1949032, you want to display 1,949,032.1

JavaScript’s built-in support for formatting numbers is limited, but includes support for a fixed number of decimal digits, fixed precision, and exponential notation. Furthermore, there is support for displaying numbers in other bases, such as binary, octal, and hexadecimal.

By necessity, all of JavaScript’s number formatting methods return a string, not a number; only a string can preserve the desired formatting (it is easy to convert back to a number if necessary, however). The upshot of this is that you should only format numbers immediately before displaying them; while you are storing them or using them in calculations, they should remain unformatted number types.

Fixed Decimals

If you want a fixed number of digits past the decimal point, you can use Number.prototype.toFixed:

const x = 19.51;

x.toFixed(3); // "19.510"

x.toFixed(2); // "19.51"

x.toFixed(1); // "19.5"

x.toFixed(0); // "20"

Note that this is not truncation: the output is rounded to the number of specified decimal digits.

Exponential Notation

If you wish to display numbers in exponential notation, use Number.prototype.toExponential:

const x = 3800.5;

x.toExponential(4); // "3.8005e+4";

x.toExponential(3); // "3.801e+4";

x.toExponential(2); // "3.80e+4";

x.toExponential(1); // "3.8e+4";

x.toExponential(0); // "4e+4";

Like Number.prototype.toFixed, output is rounded, not truncated. The specified precision is the number of digits past the decimal.

Fixed Precision

If what you care about is a fixed number of digits (regardless of where the decimal place falls), you can use Number.prototype.toPrecision:

let x = 1000;

x.toPrecision(5); // "1000.0"

x.toPrecision(4); // "1000"

x.toPrecision(3); // "1.00e+3"

x.toPrecision(2); // "1.0e+3"

x.toPrecision(1); // "1e+3"

x = 15.335;

x.toPrecision(6); // "15.3350"

x.toPrecision(5); // "15.335"

x.toPrecision(4); // "15.34"

x.toPrecision(3); // "15.3"

x.toPrecision(2); // "15"

x.toPrecision(1); // "2e+1"

Output is rounded, and will always have the specified number of digits of precision. If necessary, output will be in exponential notation.

Different Bases

If you want to display numbers in a different base (such as binary, octal, or hexadecimal), Number.prototype.toString takes an argument specifying the base (in the range 2 to 36):

const x = 12;

x.toString(); // "12" (base 10)

x.toString(10); // "12" (base 10)

x.toString(16); // "c" (hexadecimal)

x.toString(8); // "14" (octal)

x.toString(2); // "1100" (binary)

Advanced Number Formatting

If you’re displaying a lot of numbers in your application, your needs may quickly surpass what the built-in JavaScript methods provide. Common needs are:

§ Thousands separators

§ Displaying negative numbers differently (for example, with parentheses)

§ Engineering notation (similar to exponential notation)

§ SI prefixes (milli-, micro-, kilo-, mega-, etc.)

Providing this functionality can be educational if you’re looking for a reader’s exercise. If you’re not, I recommend the Numeral.js library, which provides all of this functionality and more.

Constants

The usual important constants are available as properties of the Math object:

// fundamental constants

Math.E // the root of the natural logarithm: ~2.718

Math.PI // the ratio of a circle's circumference to its diameter: ~3.142

// logarithmic convenience constants -- these can be accessed through library

// calls, but they're commonly used enough to warrant convenience constants

Math.LN2 // the natural logarithm of 2: ~0.693

Math.LN10 // the natural logarithm of 10: ~2.303

Math.LOG2E // the base 2 logarithm of Math.E: ~1.433

Math.LOG10E // the base 10 logarithm of Math.E: 0.434

// algebraic convenience constants

Math.SQRT1_2 // the square root of 1/2: ~0.707

Math.SQRT2 // the square root of 2: ~1.414

Algebraic Functions

Exponentiation

The basic exponentiation function is Math.pow, and there are convenience functions for square root, cube root, and powers of e, as shown in Table 16-1.

Function

Description

Examples

Math.pow(x, y)

x Superscript y

Math.pow(2, 3) // 8

Math.pow(1.7, 2.3) // ~3.39

Math.sqrt(x)

StartRoot x EndRoot
Equivalent to Math.pow(x, 0.5)

Math.sqrt(16) // 4

Math.sqrt(15.5) // ~3.94

Math.cbrt(x)

Cube root of x
Equivalent to Math.pow(x, 1/3)

Math.cbrt(27) // 3

Math.cbrt(22) // ~2.8

Math.exp(x)

e Superscript x Equivalent to Math.pow(Math.E, x)

Math.exp(1) // ~2.718

Math.exp(5.5) // ~244.7

Math.expm1(x)

e Superscript x Baseline minus 1 Equivalent to Math.exp(x) - 1

Math.expm1(1) // ~1.718

Math.expm1(5.5) // ~243.7

Math.hypot(x1, x2,...)

Square root of sum of arguments: StartRoot x 1 squared plus x 2 squared plus period period period EndRoot

Math.hypot(3, 4) // 5

Math.hypot(2, 3, 4) // ~5.36

Table 16-1. Exponentiation functions

Logarithmic Functions

The basic natural logarithm function is Math.log. In some languages, “log” refers to “log base 10” and “ln” refers to “natural logarithm,” so keep in mind that in JavaScript, “log” means “natural logarithm.” ES6 introduced Math.log10 for convenience.

Function

Description

Examples

Math.log(x)

Natural logarithm of x

Math.log(Math.E) // 1

Math.log(17.5) // ~2.86

Math.log10(x)

Base 10 logarithm of x
Equivalent to Math.log(x)/Math.log(10)

Math.log10(10) // 1

Math.log10(16.7) // ~1.22

Math.log2(x)

Base 2 logarithm of x
Equivalent to Math.log(x)/Math.log(2)

Math.log2(2) // 1

Math.log2(5) // ~2.32

Math.log1p(x)

Natural logarithm of 1 plus x
Equivalent to Math.log(1 + x)

Math.log1p(Math.E - 1) // 1

Math.log1p(17.5) // ~2.92

Table 16-2. Logarithmic functions

Miscellaneous

Table 16-3 lists miscellaneous numeric functions that allow you to perform common operations such as finding the absolute value, ceiling, floor, or sign of a number, as well as finding the minimum or maximum number in a list.

Function

Description

Examples

Math.abs(x)

Absolute value of x

Math.abs(-5.5) // 5.5

Math.abs(5.5) // 5.5

Math.sign(x)

The sign of x: if x is negative, –1; if x is positive, 1; and if x is 0, 0

Math.sign(-10.5) // -1

Math.sign(6.77) // 1

Math.ceil(x)

The ceiling of x: the smallest integer greater than or equal to x

Math.ceil(2.2) // 3

Math.ceil(-3.8) // -3

Math.floor(x)

The floor of x: the largest integer less than or equal to x

Math.floor(2.8) // 2

Math.floor(-3.2) // -4

Math.trunc(x)

The integral part of x (all fractional digits removed)

Math.trunc(7.7) // 7

Math.trunc(-5.8) // -5

Math.round(x)

x rounded to the nearest integer

Math.round(7.2) // 7

Math.round(7.7) // 8

Math.round(-7.7) // -8

Math.round(-7.2) // -7

Math.min(x1, x2,...)

Returns the minimum argument

Math.min(1, 2) // 1

Math.min(3, 0.5, 0.66) // 0.5

Math.min(3, 0.5, -0.66) // -0.66

Math.max(x1, x2,...)

Returns the maximum argument

Math.max(1, 2) // 2

Math.max(3, 0.5, 0.66) // 3

Math.max(-3, 0.5, -0.66) // 0.5

Table 16-3. Number miscellaneous algebraic functions

Pseudorandom Number Generation

Pseudorandom number generation is provided by Math.random, which returns a pseudorandom number greater than or equal to 0 and less than 1. You may recall from algebra that number ranges are often denoted with square brackets (inclusive) and parentheses (exclusive). In this notation,Math.random returns numbers in the range [0, 1).

Math.random does not provide any convenience methods for providing pseudorandom numbers in different ranges. Table 16-4 shows some general formulas for getting other ranges. In this table, x and y denote real numbers and m and n denote integers.

Range

Example

[0, 1)

Math.random()

[x, y)

x + (y-x)*Math.random()

Integer in [m, n)

m + Math.floor((n-m)*Math.random())

Integer in [m, n]

m + Math.floor((n-m+1)*Math.random())

Table 16-4. Number pseudorandom number generation

A common complaint about JavaScript’s pseudorandom number generator is that it can’t be seeded, which is important to testing some algorithms involving pseudorandom numbers. If you need seeded pseudorandom numbers, see David Bau’s seedrandom.js package.

NOTE

It is common (but incorrect) for pseudorandom number generators (PRNGs) to simply be called “random number generators.” PRNGs produce numbers that for most practical applications appear to be random, but true random number generation is a very difficult problem.

Trigonometric Functions

There are no surprises here. Sine, cosine, tangent, and their inverses are all available, as shown in Table 16-5. All trigonometric functions in the Math library operate on radians, not degrees.

Function

Description

Examples

Math.sin(x)

Sine of x radians

Math.sin(Math.PI/2) // 1

Math.sin(Math.PI/4) // ~0.707

Math.cos(x)

Cosine of x radians

Math.cos(Math.PI) // -1

Math.cos(Math.PI/4) // ~0.707

Math.tan(x)

Tangent of x radians

Math.tan(Math.PI/4) // ~1

Math.tan(0) // 0

Math.asin(x)

Inverse sine (arcsin) of x (result in radians)

Math.asin(0) // 0

Math.asin(Math.SQRT1_2) // ~0.785

Math.acos(x)

Inverse cosine (arccos) of x (result in radians)

Math.acos(0) // ~1.57+

Math.acos(Math.SQRT1_2) // ~0.785+

Math.atan(x)

Inverse tangent (arctan) of x (result in radians)

Math.atan(0) // 0

Math.atan(Math.SQRT1_2) // ~0.615

Math.atan2(y, x0)

Counterclockwise angle (in radians) from the x-axis to the point (x, y)

Math.atan2(0, 1) // 0

Math.atan2(1, 1) // ~0.785

Table 16-5. Number trigonometric functions

If you’re dealing with degrees, you’ll need to convert them to radians. The calculation is easy: divide by 180 and multiply by π. It’s easy to write helper functions:

function deg2rad(d) { return d/180*Math.PI; }

function rad2deg(r) { return r/Math.PI*180; }

Hyperbolic Functions

Like the trigonometric functions, the hyperbolic functions are standard, as you can see in Table 16-6.

Function

Description

Examples

Math.sinh(x)

Hyperbolic sine of x

Math.sinh(0) // 0

Math.sinh(1) // ~1.18

Math.cosh(x)

Hyperbolic cosine of x

Math.cosh(0) // 1

Math.cosh(1) // ~1.54

Math.tanh(x)

Hyperbolic tangent of x

Math.tanh(0) // 0

Math.tanh(1) // ~0.762

Math.asinh(x)

Inverse hyperbolic sine (arcsinh) of x

Math.asinh(0) // 0

Math.asinh(1) // ~0.881

Math.acosh(x)

Inverse hyperbolic cosine (arccosh) of x

Math.acosh(0) // NaN

Math.acosh(1) // 0

Math.atanh(x)

Inverse hyperbolic tangent (arctanh) of x

Math.atanh(0) // 0

Math.atanh(0) // ~0.615

Table 16-6. Number hyperbolic functions

1In some cultures, periods are used as thousands separators, and commas are used as the decimal separator, opposite from what you may be used to.