`Math` object

This article explains about the Math object.

It explains step by step, from basic usage to common practical patterns, as well as pitfalls and countermeasures.

YouTube Video

Math object

JavaScript's Math object provides a set of built-in utilities for numerical calculations.

Constants

Constants defined in Math are useful when dealing with high-precision values.

The following code shows some typical constants.

1// Show common Math constants
2console.log("Math.PI:", Math.PI);         // 3.141592653589793
3console.log("Math.E:", Math.E);           // Euler's number
4console.log("Math.LN2:", Math.LN2);       // Natural log of 2
5console.log("Math.SQRT2:", Math.SQRT2);   // Square root of 2
  • These constants can be used as is for trigonometric functions, logarithmic conversions, normalization, and more. For example, Math.PI is needed to convert angles to radians.

Basic rounding and absolute values (abs, floor, ceil, round, trunc)

Rounding and handling signs are frequently used, so it's important to properly understand the differences between Math.floor, Math.ceil, and Math.round. Especially when handling negative numbers, results may differ from intuition, so it is necessary to be careful about how each rounding rule works and use them appropriately.

The following examples illustrate the differences between rounding functions.

 1// Examples of rounding and absolute value functions
 2const pos = 3.7;
 3const neg = -3.7;
 4
 5// --- floor ---
 6console.log("Math.floor(3.7):", Math.floor(pos));  // 3
 7console.log("Math.floor(-3.7):", Math.floor(neg)); // -4
 8// (rounds toward smaller value)
 9
10// --- ceil ---
11console.log("Math.ceil(3.7):", Math.ceil(pos));  // 4
12console.log("Math.ceil(-3.7):", Math.ceil(neg)); // -3
13// (rounds toward larger value)
14
15// --- round ---
16console.log("Math.round(3.5):", Math.round(3.5));   // 4
17// (.5 goes up for positive numbers)
18console.log("Math.round(-3.5):", Math.round(-3.5)); // -3
19// (.5 moves toward zero for negative numbers)
20
21// --- trunc ---
22console.log("Math.trunc(3.7):", Math.trunc(pos));  // 3
23console.log("Math.trunc(-3.7):", Math.trunc(neg)); // -3
24// (fraction removed toward zero)
25
26// --- abs ---
27console.log("Math.abs(-3.7):", Math.abs(neg)); // 3.7
  • Math.floor rounds towards the smaller direction for negative numbers, so -3.7 becomes -4.
  • Math.ceil rounds towards the larger direction for negative numbers, so -3.7 becomes -3.
  • Math.round rounds .5 up for positive numbers, and for negative numbers, it rounds towards zero.
  • Negative numbers can produce results that differ from intuition, so it is important to clearly understand in which direction numbers are being rounded.
  • Rounding functions should be selected according to the use case. For example, use Math.floor for index calculations, Math.ceil for upper limits, and Math.trunc when you just want to drop the decimal part.

Multiplication, exponentiation, and roots (pow, **, sqrt, cbrt, hypot)

Exponentiation and square roots can be done with Math.pow or with the ** operator. Math.hypot safely calculates the square root of the sum of squares (distance).

Below are examples of exponentiation and hypot. Math.hypot mitigates the impact of overflow and underflow.

1// Power, root and hypot examples
2console.log("2 ** 10:", 2 ** 10);                // 1024
3console.log("Math.pow(2, 10):", Math.pow(2, 10));// 1024
4console.log("Math.sqrt(16):", Math.sqrt(16));    // 4
5console.log("Math.cbrt(27):", Math.cbrt(27));    // 3
6console.log("Math.hypot(3, 4):", Math.hypot(3, 4));// 5 (3-4-5 triangle)
  • Math.hypot is useful when dealing with triangle sides or multi-dimensional vector lengths.

Exponential and logarithmic functions (exp, log, log10, log2)

Exponentials and logarithms are often used in probability, exponential decay, and scaling.

Next are basic examples of exp and logarithms. Make sure to use the appropriate function, depending on the logarithm base.

1// Exponential and logarithm examples
2console.log("Math.exp(1):", Math.exp(1));     // e^1
3console.log("Math.log(Math.E):", Math.log(Math.E)); // natural log, 1
4console.log("Math.log10(100):", Math.log10(100));   // 2
5console.log("Math.log2(8):", Math.log2(8));         // 3
  • Natural logarithms (Math.log) are standard in statistics and differential equations. Common logarithms and base-2 logarithms are also chosen depending on the application.

Trigonometric functions (sin, cos, tan, asin, acos, atan2)

Trigonometric functions are essential for angle calculations, rotations, and coordinate transformations. Math.atan2(y, x) is useful for calculating angles while considering quadrants correctly.

Below are basic examples and usage of atan2. Angles must be handled in radians.

 1// Trigonometry examples (angles in radians)
 2const degToRad = deg => deg * (Math.PI / 180);
 3const radToDeg = rad => rad * (180 / Math.PI);
 4
 5console.log("Math.sin(PI/2):", Math.sin(Math.PI / 2));          // 1
 6console.log("Math.cos(0):", Math.cos(0));                      // 1
 7console.log("Math.tan(Math.PI / 4):", Math.tan(Math.PI / 4));  // ~1
 8
 9// Using atan2 to compute angle of vector (x, y)
10const x = -1, y = 1;
11const angle = Math.atan2(y, x); // returns angle in radians taking quadrant into account
12console.log("atan2(1, -1) in degrees:", radToDeg(angle));      // 135
  • atan2 can safely determine the angle of a vector, making it preferable for rotations and heading calculations.

Random number generation (Math.random and practical patterns)

Math.random() returns a uniformly distributed random number in the range [0, 1). You can convert or extend it as needed for integer ranges or normal distributions, for example.

The following are examples of random number utility functions. If you need cryptographically secure random numbers, use crypto.getRandomValues.

 1// Random utilities using Math.random
 2
 3// Get integer in [min, max] inclusive
 4function randomInt(min, max) {
 5  // Returns integer between min and max (inclusive)
 6  return Math.floor(Math.random() * (max - min + 1)) + min;
 7}
 8console.log("randomInt(1, 6):", randomInt(1, 6)); // dice roll example
 9
10// Get float in [min, max)
11function randomFloat(min, max) {
12  return Math.random() * (max - min) + min;
13}
14console.log("randomFloat(0, 5):", randomFloat(0, 5));
15
16// Fisher-Yates shuffle
17function shuffle(array) {
18  for (let i = array.length - 1; i > 0; i--) {
19    const j = Math.floor(Math.random() * (i + 1));
20    // swap array[i] and array[j]
21    [array[i], array[j]] = [array[j], array[i]];
22  }
23  return array;
24}
25console.log("shuffle([1,2,3,4,5]):", shuffle([1,2,3,4,5]));
  • Math.random is convenient for general use, but for game replays or cryptography, countermeasures for reproducibility or security are required.

Practical helpers (clamp, lerp, mapRange, angle normalization)

It’s helpful to write small utility functions yourself for frequently used mathematical tasks.

Here are implementation examples of commonly used utilities.

 1// Utility functions: clamp, lerp, mapRange, normalizeAngle
 2
 3// Clamp value between min and max
 4function clamp(v, min, max) {
 5  return Math.max(min, Math.min(max, v));
 6}
 7console.log("clamp(10, 0, 5):", clamp(10, 0, 5)); // 5
 8
 9// Linear interpolation: t in [0,1]
10function lerp(a, b, t) {
11  return a + (b - a) * t;
12}
13console.log("lerp(0, 10, 0.25):", lerp(0, 10, 0.25)); // 2.5
14
15// Map value from one range to another
16function mapRange(v, inMin, inMax, outMin, outMax) {
17  const t = (v - inMin) / (inMax - inMin);
18  return lerp(outMin, outMax, t);
19}
20console.log("mapRange(5, 0, 10, 0, 100):", mapRange(5, 0, 10, 0, 100));
21// -> 50
22
23// Normalize angle to [-PI, PI)
24function normalizeAngle(rad) {
25  return Math.atan2(Math.sin(rad), Math.cos(rad));
26}
27console.log("normalizeAngle(3*PI):", normalizeAngle(3 * Math.PI));
  • This code collects small utility functions commonly used for numerical operations such as clamping values, interpolation, range mapping, and angle normalization. clamp limits a value to a specified range, while lerp and mapRange perform smooth interpolation or conversion to another range. Additionally, normalizeAngle always normalizes angles to the range [-π, π) to stabilize rotation calculations.
  • These helpers are frequently used in graphics, games, and interaction programming. normalizeAngle is important for comparing angular differences and for interpolation.

Floating-point and rounding caveats (precision and comparison)

JavaScript numbers are IEEE-754 double-precision floating-point (64-bit), so caution is required when comparing or rounding numbers. For example, 0.1 + 0.2 !== 0.3.

Here is an example of handling rounding errors. It is important to use comparisons that tolerate small errors, or appropriate rounding functions.

1// Floating point precision example and safe equality
2console.log("0.1 + 0.2 === 0.3 :", 0.1 + 0.2 === 0.3); // false
3
4function nearlyEqual(a, b, eps = 1e-12) {
5  return Math.abs(a - b) <= eps;
6}
7console.log("nearlyEqual(0.1+0.2, 0.3):", nearlyEqual(0.1 + 0.2, 0.3));
8// -> true
  • For robust numerical equality checks, use absolute error (eps) or relative error.

Performance tips

The functions of Math are optimized natively and are often faster than hand-written equivalent logic. If the same calculation (e.g., Math.PI / 180) is repeated in a loop, assigning it to a variable in advance reduces unnecessary overhead.

Below is an example of converting degrees to radians by creating a constant outside a loop.

1// Cache conversion factor for performance
2const DEG_TO_RAD = Math.PI / 180;
3const RAD_TO_DEG = 180 / Math.PI;
4
5for (let deg = 0; deg < 360; deg += 10) {
6  // Use cached constant instead of computing each time
7  const rad = deg * DEG_TO_RAD;
8  // ... do work with rad
9}
  • It's best to verify actual hotspots with a profiler before performing optimizations.
  • It is efficient to cache constants that are used frequently.

Compatibility and polyfills

Math itself has existed for a long time, but some functions like Math.cbrt, Math.log10, Math.log2, and Math.hypot may be unsupported in older environments. Prepare a simple polyfill if necessary.

Below is an example of a simple polyfill for Math.log2.

1// Polyfill for Math.log2 if needed
2if (!Math.log2) {
3  Math.log2 = function(x) {
4    return Math.log(x) / Math.LN2;
5  };
6}
7console.log("Math.log2(8):", Math.log2(8));

Many environments already support them, but check for compatibility if required.

Check browser support according to your project's target environment.

Practical example: Time-stepped updates in a simple physics simulation

Finally, here is a practical example combining several Math functions. This is a very simple example for updating position, velocity, and angle control.

It's a highly simplified model of a physics engine.

 1// Clamp value between min and max
 2function clamp(v, min, max) {
 3  return Math.max(min, Math.min(max, v));
 4}
 5
 6// Normalize angle to [-PI, PI)
 7function normalizeAngle(rad) {
 8  return Math.atan2(Math.sin(rad), Math.cos(rad));
 9}
10
11// Simple physics step example using Math utilities
12function step(state, dt) {
13  // state: { x, y, vx, vy, angle, angularVelocity }
14  // dt: time delta in seconds
15  // Integrate linear motion
16  state.x += state.vx * dt;
17  state.y += state.vy * dt;
18
19  // Integrate angular motion and normalize angle
20  state.angle = normalizeAngle(state.angle + state.angularVelocity * dt);
21
22  // Keep position within bounds [0, width] x [0, height]
23  state.x = clamp(state.x, 0, state.width);
24  state.y = clamp(state.y, 0, state.height);
25  return state;
26}
27
28const state = { x: 10, y: 10, vx: 2, vy: 0.5, angle: 0, angularVelocity: 0.1, width: 100, height: 100 };
29console.log("before:", state);
30step(state, 0.016); // simulate ~1 frame at 60fps
31console.log("after:", state);
  • By combining Math helpers like this, simulation and animation logic can be made more concise.

Summary

  • Math covers everything from constants and basic functions to advanced ones, serving as the foundation for numerical processing.
  • Select functions according to their purpose, such as random numbers, trigonometric functions, exponentials/logarithms, or rounding; and create small utilities like clamp and lerp for practical use.
  • Pay attention to floating-point precision and the support status of your target environment, and prepare error tolerance or polyfills if necessary.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video