Numbers & Math

JavaScript · Lesson 10 of 61 7 min read Updated

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.

JavaScriptRun it yourself
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));
Output
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.

JavaScriptRun it yourself
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));
Output
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 (1050 for ₹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.

JavaScriptRun it yourself
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")));
Output
42
NaN
42
3.75
0
NaN
true
  • Number() is strict: the whole string must be a number, or you get NaN. An empty string becomes 0, 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" gives NaN. Remove them first with replaceAll(",", "").

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.

JavaScriptRun it yourself
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));
Output
488
487
488
-4
89
56
15
12
3.1416
FunctionDoesExample
Math.round(x)Nearest whole number487.6 becomes 488
Math.floor(x)Round down487.6 becomes 487
Math.ceil(x)Round up487.1 becomes 488
Math.trunc(x)Drop the decimal part-4.7 becomes -4
Math.max(...) / Math.min(...)Largest / smallestof any number of values
Math.abs(x)Distance from zero-15 becomes 15
Math.random()Random decimal from 0 up to (not including) 10.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:

JavaScriptRun it yourself
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:

JavaScript
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" + 20 is "50020". Convert first.
  • Comparing with NaN. x === NaN is always false. Use Number.isNaN(x).
  • Doing more maths after toFixed(). It returns a string, so price.toFixed(2) + 10 joins text.
  • Expecting exact decimals. Use paise for money and round only for display.

Key points

  • JavaScript has one number type for whole numbers and decimals.
  • Numeric separators like 1_00_000 make long numbers readable.
  • Decimals are approximate: 0.1 + 0.2 is 0.30000000000000004; store money as paise.
  • Number() is strict; parseInt() and parseFloat() read from the start of a string.
  • Math has round, floor, ceil, max, min, abs, random and more.
  • BigInt (123n) handles whole numbers beyond Number.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
JavaScript
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));
Output
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?

2. What is parseInt("15 years")?

3. Which expression gives a random whole number from 1 to 10?

4. What type does (19.5).toFixed(2) return?

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