Numbers & Math
Prices, marks, distances, percentages and scores are all numbers, so almost every program does some maths. JavaScript makes simple maths easy, but it has a few surprises, especially with decimals, that every developer has to learn once.
In this lesson you will learn how JavaScript stores numbers, why 0.1 + 0.2 is not exactly 0.3, how to turn text into numbers, and how to use the built-in Math object.
One type for all numbers
Many languages have separate types for whole numbers and decimals. JavaScript has just one, number, for both. Every number is stored in a 64-bit format called floating point.
You can make long numbers easier to read with numeric separators: underscores between digits. JavaScript ignores them, so you can even group digits the Indian way, in lakhs and crores.
const population = 1_00_000;
const projectBudget = 2_50_00_000;
const price = 1299.5;
const distance = 2.5e3; // 2.5 x 1000
console.log(population, projectBudget, price, distance);
console.log(typeof population, typeof price);
console.log(Number.isInteger(population), Number.isInteger(price));100000 25000000 1299.5 2500 number number true false
2.5e3 is scientific notation, a short way to write 2.5 times 10 to the power 3. Number.isInteger() tells you whether a number is whole.
The decimal problem: 0.1 + 0.2
Computers store numbers in binary (base 2). Some simple decimals, like 0.1, cannot be written exactly in binary, just as 1/3 cannot be written exactly in decimal (0.3333...). The stored value is extremely close, but not exact, and the tiny error can show up after a calculation.
console.log(0.1 + 0.2);
console.log(0.1 + 0.2 === 0.3);
// ₹10.50 + ₹20.99, stored as whole paise instead
const totalPaise = 1050 + 2099;
console.log(totalPaise / 100);
console.log((0.1 + 0.2).toFixed(2));
console.log(typeof (0.1 + 0.2).toFixed(2));0.30000000000000004 false 31.49 0.30 string
This is not a JavaScript bug; Python, Java and most other languages give the same result. Three ways to deal with it:
- Use whole numbers for money. Store paise instead of rupees (
1050for ₹10.50), do the maths, and divide by 100 only for display. Whole numbers up to about nine quadrillion are exact. - Round for display.
toFixed(2)rounds to 2 decimal places. It returns a string, so use it only for showing the result, not for further maths. - Never compare decimals with
===. Check whether the difference is tiny instead, or round first.
Converting text to numbers
Values from forms, URLs and files arrive as strings. You met Number() in Data Types. Two more functions read a number from the start of a string and ignore what follows.
console.log(Number("42"));
console.log(Number("42px"));
console.log(parseInt("42px"));
console.log(parseFloat("3.75 kg"));
console.log(Number(""));
console.log(Number("1,299"));
console.log(Number.isNaN(Number("abc")));42 NaN 42 3.75 0 NaN true
Number()is strict: the whole string must be a number, or you getNaN. An empty string becomes0, which can hide a missing value, so check for empty input first.parseInt()reads a whole number from the start;parseFloat()also reads decimals.- Commas are not understood, so
"1,299"givesNaN. Remove them first withreplaceAll(",", "").
NaN means "Not a Number", the result of maths that failed. Strangely, NaN is not equal to anything, not even itself, so x === NaN is always false. Use Number.isNaN(x) to test for it.
The Math object
Math is a built-in object full of maths functions and constants. You do not create it; you just use it.
const bill = 487.6;
console.log(Math.round(bill));
console.log(Math.floor(bill));
console.log(Math.ceil(bill));
console.log(Math.trunc(-4.7));
console.log(Math.max(56, 89, 72));
console.log(Math.min(56, 89, 72));
console.log(Math.abs(-15));
console.log(Math.sqrt(144));
console.log(Math.PI.toFixed(4));488 487 488 -4 89 56 15 12 3.1416
| Function | Does | Example |
|---|---|---|
Math.round(x) | Nearest whole number | 487.6 becomes 488 |
Math.floor(x) | Round down | 487.6 becomes 487 |
Math.ceil(x) | Round up | 487.1 becomes 488 |
Math.trunc(x) | Drop the decimal part | -4.7 becomes -4 |
Math.max(...) / Math.min(...) | Largest / smallest | of any number of values |
Math.abs(x) | Distance from zero | -15 becomes 15 |
Math.random() | Random decimal from 0 up to (not including) 1 | 0.4372... |
To round to two decimal places and keep a number, multiply, round and divide: Math.round(x * 100) / 100.
Random whole numbers
Math.random() gives a decimal such as 0.734. To get a whole number in a range, scale it, round it down and shift it. This rolls a dice for a game of Ludo:
const dice = Math.floor(Math.random() * 6) + 1;
console.log("You rolled", dice);Math.random() * 6 gives a decimal from 0 up to 5.999..., Math.floor() turns it into 0 to 5, and + 1 makes it 1 to 6. Run it a few times. Math.random() is fine for games, but it is not secure; never use it for passwords or OTPs.
Very big numbers: BigInt
Normal numbers are exact only up to Number.MAX_SAFE_INTEGER, which is 9007199254740991. Beyond that, results can be wrong. For larger whole numbers, add an n to make a BigInt:
console.log(9007199254740992 + 1); // 9007199254740992 (wrong)
console.log(9007199254740992n + 1n); // 9007199254740993n (exact)You cannot mix BigInt and normal numbers in one calculation (5n + 1 throws a TypeError), and BigInt has no decimals. You will rarely need it, except for things like very large IDs.
Common mistakes
- Doing maths on strings.
"500" + 20is"50020". Convert first. - Comparing with
NaN.x === NaNis alwaysfalse. UseNumber.isNaN(x). - Doing more maths after
toFixed(). It returns a string, soprice.toFixed(2) + 10joins text. - Expecting exact decimals. Use paise for money and round only for display.
Key points
- JavaScript has one
numbertype for whole numbers and decimals. - Numeric separators like
1_00_000make long numbers readable. - Decimals are approximate:
0.1 + 0.2is0.30000000000000004; store money as paise. Number()is strict;parseInt()andparseFloat()read from the start of a string.Mathhasround,floor,ceil,max,min,abs,randomand more.- BigInt (
123n) handles whole numbers beyondNumber.MAX_SAFE_INTEGER.
Exercise
A customer in Kochi buys 3 items priced "249.50", "99.99" and "1,150" (these came from a form as strings). Convert them to numbers, find the total in paise to avoid decimal errors, and print the total in rupees with exactly two decimal places. Also print the most expensive item using Math.max().
Show solution
const prices = ["249.50", "99.99", "1,150"];
const p1 = Number(prices[0]);
const p2 = Number(prices[1]);
const p3 = Number(prices[2].replaceAll(",", ""));
const totalPaise = Math.round(p1 * 100) + Math.round(p2 * 100) + Math.round(p3 * 100);
console.log("Total: ₹" + (totalPaise / 100).toFixed(2));
console.log("Costliest: ₹" + Math.max(p1, p2, p3));Total: ₹1499.49 Costliest: ₹1150
The comma must be removed before Number() can read "1,150". Converting each price to whole paise with Math.round(x * 100) keeps the sum exact, and toFixed(2) is used only for display.
Quick Quiz
1. What does 0.1 + 0.2 === 0.3 give in JavaScript?
0.1 and 0.2 cannot be stored exactly in binary, so their sum is 0.30000000000000004.
2. What is parseInt("15 years")?
parseInt() reads digits from the start of the string and stops at the first character that is not part of a number.
3. Which expression gives a random whole number from 1 to 10?
Math.floor(Math.random() * 10) gives 0 to 9, and adding 1 shifts the range to 1 to 10.
4. What type does (19.5).toFixed(2) return?
toFixed() returns a formatted string such as "19.50", meant for display.
Learn JavaScript with a mentor
Free lessons get you started. Our Full Stack Web Development training adds real projects and code reviews from working developers.
- Project-based learning
- Mentor code reviews
- Free counselling call
