Skip to content
C Codeloom
JavaScript

Numbers and Math in JavaScript

A complete beginner's guide to numbers in JavaScript — arithmetic, the Math object, rounding, formatting, NaN, Infinity, and the floating-point quirk every developer must know.

·8 min read · By Yash Kesharwani
Beginner 10 min read

What you'll learn

  • Every arithmetic operator and how precedence works
  • The Math object — rounding, powers, roots, random
  • How to format numbers for display
  • What NaN and Infinity actually are
  • The 0.1 + 0.2 floating-point quirk and how to handle it

Prerequisites

Almost every program does some arithmetic — a total, an average, a price, a percentage, a coordinate. JavaScript’s number system is small enough to learn quickly, with one well-known quirk that surprises every newcomer once and then never again.

Arithmetic operators

The five basic operators behave as you’d expect:

console.log(7 + 2);    // 9   addition
console.log(7 - 2);    // 5   subtraction
console.log(7 * 2);    // 14  multiplication
console.log(7 / 2);    // 3.5 division — always a float
console.log(7 % 2);    // 1   remainder ("modulo")
console.log(7 ** 2);   // 49  exponentiation

A few things worth flagging:

  • Division never floors. 7 / 2 is 3.5, not 3. If you want integer division, use Math.floor(7 / 2) or Math.trunc(7 / 2).
  • % is remainder, not modulo in the strict mathematical sense. For positive numbers they’re identical. For negatives, -7 % 3 is -1, which sometimes matters.
  • ** is the modern exponentiation operator (since 2016). Before that, you wrote Math.pow(7, 2).

Operator precedence

JavaScript follows the standard order of operations:

console.log(2 + 3 * 4);       // 14  — * before +
console.log((2 + 3) * 4);     // 20
console.log(2 ** 3 ** 2);     // 512 — ** is right-associative: 2 ** (3 ** 2)

When in doubt, add parentheses. Parentheses make code easier to read at no cost.

Compound assignment

Each operator has a shorthand for “do this with the variable’s own value”:

let n = 10;
n += 5;    // n = n + 5  → 15
n -= 3;    // n = n - 3  → 12
n *= 2;    // n = n * 2  → 24
n /= 4;    // n = n / 4  → 6
n %= 4;    // n = n % 4  → 2
n **= 3;   // n = n ** 3 → 8

And the two unary shortcuts:

let i = 0;
i++;       // i = i + 1
i--;       // i = i - 1

You’ll see i++ constantly inside for loops. We’ll use it in Conditionals and Loops.

The Math object

Math is a built-in object containing constants and utility functions. You don’t construct it — you just use it directly.

Constants

console.log(Math.PI);       // 3.141592653589793
console.log(Math.E);        // 2.718281828459045

Rounding

Math.round(2.4);    // 2   — nearest
Math.round(2.5);    // 3
Math.floor(2.9);    // 2   — round down
Math.ceil(2.1);     // 3   — round up
Math.trunc(2.9);    // 2   — drop the decimal part
Math.trunc(-2.9);   // -2  — differs from floor on negatives

Absolute value, min, max

Math.abs(-7);             // 7
Math.min(3, 1, 4, 1, 5);  // 1
Math.max(3, 1, 4, 1, 5);  // 5

min and max take any number of arguments. To pass an array, use spread:

const scores = [82, 47, 91, 56];
console.log(Math.max(...scores));   // 91

Powers, roots, logs

Math.sqrt(16);      // 4
Math.cbrt(27);      // 3
Math.pow(2, 10);    // 1024  — same as 2 ** 10
Math.log(Math.E);   // 1     — natural log
Math.log10(1000);   // 3
Math.log2(1024);    // 10

Trigonometry

Math.sin(0);        // 0
Math.cos(0);        // 1
Math.tan(Math.PI / 4); // 0.9999999999999999 — close enough to 1

All trig functions work in radians, not degrees. Convert with degrees * Math.PI / 180.

Random numbers

Math.random() returns a float in the range [0, 1) — including 0, excluding 1:

console.log(Math.random());   // e.g. 0.7283456...

For a random integer in a range, use floor:

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

console.log(randomInt(1, 6));   // simulate a die roll

Try it yourself. Write a function circleArea(radius) that returns the area of a circle. Test it with circleArea(5) (should be about 78.54). Then write coinFlip() that returns the string "heads" or "tails" with 50/50 odds.

Formatting numbers for display

Number and Math give you raw numbers. To format them for humans, JavaScript provides three useful methods.

toFixed — decimal places as a string

const price = 19.4;
console.log(price.toFixed(2));    // '19.40' — note: a string
console.log(price.toFixed(0));    // '19'

toFixed returns a string, not a number. That’s usually what you want for display.

toLocaleString — locale-aware formatting

const n = 1234567.89;
console.log(n.toLocaleString("en-US"));   // '1,234,567.89'
console.log(n.toLocaleString("de-DE"));   // '1.234.567,89'
console.log(n.toLocaleString("en-IN"));   // '12,34,567.89'

For currencies:

const price = 19.4;
console.log(price.toLocaleString("en-US", {
  style: "currency",
  currency: "USD",
}));                                       // '$19.40'

This single API handles thousands separators, decimal styles, currency symbols, and percentages across every locale. It is one of JavaScript’s most useful built-ins.

Number.parseInt and Number.parseFloat

When you have a string like "42px" from user input and need the number out of it:

Number.parseInt("42");          // 42
Number.parseInt("42px");        // 42  — stops at the first non-digit
Number.parseFloat("3.14em");    // 3.14
Number.parseInt("hello");       // NaN

For strict conversion that fails on any junk, use Number():

Number("42");        // 42
Number("42px");      // NaN — full string must be a valid number

NaN and Infinity

Two special values you’ll occasionally meet.

NaN

NaN stands for “Not a Number” and represents an invalid arithmetic result:

console.log(0 / 0);              // NaN
console.log(Math.sqrt(-1));      // NaN
console.log(Number("hello"));    // NaN

The strangest thing about NaN is that it is not equal to itself:

console.log(NaN === NaN);   // false

To check for NaN, use Number.isNaN:

const value = Number("hello");
if (Number.isNaN(value)) {
  console.log("not a valid number");
}

Infinity

Infinity is what you get when a number grows past JavaScript’s representable range, or from division by zero:

console.log(1 / 0);             // Infinity
console.log(-1 / 0);            // -Infinity
console.log(Number.isFinite(1 / 0));   // false
console.log(Number.isFinite(42));      // true

Number.isFinite is the cleanest “is this a real, usable number?” check.

The floating-point quirk

This catches every developer once:

console.log(0.1 + 0.2);   // 0.30000000000000004

JavaScript numbers are 64-bit floating-point values (the IEEE 754 standard). Some decimals — including 0.1 — cannot be represented exactly in binary, in the same way that 1/3 cannot be written exactly in decimal. The small error you see is the rounding error from binary representation.

This is not a bug in JavaScript — Python, Java, C#, and almost every other language do the same thing. It is a property of binary floating-point.

The two everyday fixes:

1. Round when comparing or displaying

const result = 0.1 + 0.2;
console.log(result.toFixed(2));      // '0.30'
console.log(Math.abs(result - 0.3) < 1e-9);   // true

2. Use integers for money

The standard advice for financial calculations is to store amounts as integers in the smallest unit (cents, satoshis, paise). Then your arithmetic is exact:

const priceCents = 1999;        // $19.99
const taxCents = 175;           // $1.75
const totalCents = priceCents + taxCents;
console.log(`Total: $${(totalCents / 100).toFixed(2)}`);   // 'Total: $21.74'

For very precise needs, libraries like decimal.js give you arbitrary-precision decimals.

Try it yourself. Write a function average(numbers) that takes an array of numbers and returns their average, formatted to two decimal places as a string. Test with [82, 47, 91, 56, 73] (should give '69.80').

A small worked example

Putting it all together — a tip calculator that handles the floating-point quirk by working in cents.

function calculateTip(billCents, tipPercent, people) {
  const tipCents = Math.round(billCents * (tipPercent / 100));
  const totalCents = billCents + tipCents;
  const perPersonCents = Math.ceil(totalCents / people);

  const fmt = (c) =>
    (c / 100).toLocaleString("en-US", { style: "currency", currency: "USD" });

  return {
    tip: fmt(tipCents),
    total: fmt(totalCents),
    perPerson: fmt(perPersonCents),
  };
}

console.log(calculateTip(8450, 18, 3));
// { tip: '$15.21', total: '$99.71', perPerson: '$33.24' }

Integer cents, explicit rounding, locale-aware display. That’s the professional pattern.

Recap

You now know:

  • The basic arithmetic operators, including ** for exponentiation
  • Math gives you rounding, powers, trig, and random
  • Math.random() returns [0, 1); combine with Math.floor for integer ranges
  • toFixed and toLocaleString format numbers for display
  • NaN !== NaN — use Number.isNaN to check
  • Number.isFinite for “is this a usable number?”
  • Floating-point rounding errors are real, universal, and easy to handle once you know about them

Next steps

We have spent a lot of time on numbers. The other type that shows up in nearly every program is strings — and JavaScript has a beautiful tool for them called the template literal.

→ Next: Strings and Template Literals in JavaScript

Questions or feedback? Email codeloomdevv@gmail.com.