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.
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
- •JavaScript data types — see Data Types
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 / 2is3.5, not3. If you want integer division, useMath.floor(7 / 2)orMath.trunc(7 / 2). %is remainder, not modulo in the strict mathematical sense. For positive numbers they’re identical. For negatives,-7 % 3is-1, which sometimes matters.**is the modern exponentiation operator (since 2016). Before that, you wroteMath.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 Mathgives you rounding, powers, trig, and randomMath.random()returns[0, 1); combine withMath.floorfor integer rangestoFixedandtoLocaleStringformat numbers for displayNaN !== NaN— useNumber.isNaNto checkNumber.isFinitefor “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.