JavaScriptBeginner

JavaScript Numbers and Math: Parsing, NaN and Rounding

Work with numbers in JavaScript: parse text, handle NaN and Infinity, round and format values, and use the Math object for random numbers and more.

All JavaScript lessons

What you will learn

Prices, scores, ages, percentages, dice rolls: numbers are everywhere. In this lesson you will learn how JavaScript stores numbers, how to turn text into numbers (parsing), what NaN and Infinity really mean and how to check for them, how to round and format results, and how to use the built-in Math object for things like rounding, minimum, maximum and random numbers.

Numbers in JavaScript

JavaScript has one number type for everything: whole numbers (integers) and decimals.

const students = 30;
const price = 99.99;
const temperature = -5;

console.log(typeof students, typeof price, typeof temperature);
// "number" "number" "number"

Other ways to write numbers

console.log(1_000_000);   // 1000000  (underscores make big numbers readable)
console.log(1e6);         // 1000000  (1 x 10^6)
console.log(2.5e-3);      // 0.0025
console.log(0xff);        // 255      (hexadecimal)
console.log(0b101);       // 5        (binary)

The underscore in 1_000_000 is ignored by JavaScript. It exists only to help you read the number.

The remainder and power operators (quick revision)

console.log(7 % 3);     // 1   (remainder)
console.log(-7 % 3);    // -1  (the sign follows the first number)
console.log(2 ** 10);   // 1024

Turning text into numbers (parsing)

Data from inputs, URLs and files arrives as text. To do maths with it, you must parse it into a number. You have three main tools.

Number(): strict

Number() converts the whole text. If any part is not a number, the result is NaN.

console.log(Number("42"));       // 42
console.log(Number("3.14"));     // 3.14
console.log(Number("12px"));     // NaN
console.log(Number("1,000"));    // NaN
console.log(Number(""));         // 0   (surprise!)

parseInt(): whole numbers, reads until it fails

parseInt() reads from the start and stops at the first character that does not belong. It returns whole numbers only (it cuts off the decimal part without rounding).

console.log(parseInt("42"));       // 42
console.log(parseInt("12px"));     // 12
console.log(parseInt("3.9"));      // 3   (decimal part dropped)
console.log(parseInt("  42"));     // 42  (leading spaces are fine)
console.log(parseInt("abc"));      // NaN
console.log(parseInt(""));         // NaN

parseFloat(): decimals too

console.log(parseFloat("3.14abc"));   // 3.14
console.log(parseFloat(".5"));        // 0.5
console.log(parseFloat("1e3"));       // 1000
console.log(parseFloat("abc"));       // NaN

The radix (number base)

parseInt() has an optional second value, the radix. It says which number system the text uses. It is good practice to always write it:

console.log(parseInt("42", 10));    // 42  (normal decimal numbers)
console.log(parseInt("101", 2));    // 5   (binary)
console.log(parseInt("ff", 16));    // 255 (hexadecimal)

Which one should I use?

Text Number() parseInt() parseFloat()
"42" 42 42 42
"3.9" 3.9 3 3.9
"12px" NaN 12 12
"1,000" NaN 1 1
"" 0 NaN NaN
"abc" NaN NaN NaN
  • Use Number() when the text must be a clean number (like form input). It catches mistakes such as "12abc".
  • Use parseInt() or parseFloat() when you want to pull a number out of text like "12px" or "20%".
const width = "250px";
console.log(parseInt(width, 10) + 50);   // 300

NaN: Not a Number

NaN is the result of a maths operation that does not make sense:

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

Two strange facts about NaN:

  1. Its type is "number". (typeof NaN gives "number".)
  2. It is not equal to anything, not even itself:
console.log(NaN === NaN);   // false

So you cannot check for NaN with ===. Use Number.isNaN():

console.log(Number.isNaN(NaN));       // true
console.log(Number.isNaN(42));        // false
console.log(Number.isNaN("hello"));   // false (it is text, not NaN)

Number.isNaN() vs isNaN()

There is an older global function isNaN(). It first converts the value to a number, which gives confusing answers:

console.log(isNaN("hello"));          // true   (text becomes NaN, so "true")
console.log(isNaN("123"));            // false  (text becomes 123)

console.log(Number.isNaN("hello"));   // false  (it is not the value NaN)
console.log(Number.isNaN("123"));     // false

Rule: use Number.isNaN(). It does exactly what its name says.

A very common check is to see if parsing worked:

const age = Number("twenty");

if (Number.isNaN(age)) {
  console.log("Please enter a valid number");
} else {
  console.log("Age is", age);
}

NaN spreads

Any calculation that includes NaN produces NaN, so one bad value can ruin a whole result. Check inputs early.

console.log(NaN + 5);    // NaN
console.log(NaN * 0);    // NaN

Infinity

Dividing by zero does not crash JavaScript. It gives Infinity:

console.log(1 / 0);       // Infinity
console.log(-1 / 0);      // -Infinity
console.log(Infinity + 1);   // Infinity

Check for it with Number.isFinite(), which is true only for real, normal numbers:

console.log(Number.isFinite(25));         // true
console.log(Number.isFinite(Infinity));   // false
console.log(Number.isFinite(NaN));        // false
console.log(Number.isFinite("25"));       // false (text is not a number)

Other useful checks:

console.log(Number.isInteger(5));     // true
console.log(Number.isInteger(5.5));   // false
console.log(Number.isInteger("5"));   // false

The floating-point surprise

Computers store decimals in binary, and some decimals cannot be stored exactly. So you will see results like these in every programming language:

console.log(0.1 + 0.2);          // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);  // false
console.log(0.57 * 100);         // 56.99999999999999

Fixes:

// 1. Round the result
console.log(Math.round((0.1 + 0.2) * 100) / 100);   // 0.3

// 2. Compare with a tiny allowed difference
console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);   // true

// 3. For money, count in the smallest unit (paise or cents) as whole numbers
const priceInPaise = 1999;      // ₹19.99
const totalInPaise = priceInPaise * 3;
console.log(totalInPaise / 100);   // 59.97

Big numbers

Whole numbers are only accurate up to Number.MAX_SAFE_INTEGER:

console.log(Number.MAX_SAFE_INTEGER);       // 9007199254740991
console.log(9007199254740991 + 2);          // 9007199254740992  (wrong! should be ...993)

For bigger whole numbers, use BigInt (see the data types lesson).

Formatting numbers

toFixed(): a fixed number of decimals

const price = 3.14159;

console.log(price.toFixed(2));   // "3.14"
console.log((5).toFixed(2));     // "5.00"
console.log((2.5).toFixed(0));   // "3"

Important: toFixed() returns a string, not a number. Convert back if you need to calculate:

const rounded = Number((3.14159).toFixed(2));
console.log(rounded);           // 3.14
console.log(typeof rounded);    // "number"

A small warning: toFixed() can look wrong for numbers like 1.005, because they are stored inexactly:

console.log((1.005).toFixed(2));   // "1.00"  (not "1.01")

For display of prices this is usually fine. Do the rounding at the end of your calculation, not in the middle.

toLocaleString(): commas, currency and percentages

This is the best way to show numbers to humans. It uses the number style of a country:

const amount = 1234567.891;

console.log(amount.toLocaleString("en-US"));   // "1,234,567.891"
console.log(amount.toLocaleString("en-IN"));   // "12,34,567.891"  (lakh style)

console.log(amount.toLocaleString("en-IN", {
  style: "currency",
  currency: "INR"
}));
// "₹12,34,567.89"

console.log((0.256).toLocaleString("en-US", { style: "percent" }));   // "26%"

toString() with a base

console.log((255).toString(16));   // "ff"
console.log((5).toString(2));      // "101"

The Math object

Math is a built-in toolbox of maths functions and constants. You do not create it, you just use it: Math.something().

Constants

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

Rounding: round, floor, ceil, trunc

Function What it does
Math.round(x) To the nearest whole number
Math.floor(x) Down to the next lower whole number
Math.ceil(x) Up to the next higher whole number
Math.trunc(x) Cuts off the decimal part
x round floor ceil trunc
4.2 4 4 5 4
4.5 5 4 5 4
4.8 5 4 5 4
-4.2 -4 -5 -4 -4
-4.5 -4 -5 -4 -4
-4.8 -5 -5 -4 -4
console.log(Math.round(4.5));    // 5
console.log(Math.floor(4.9));    // 4
console.log(Math.ceil(4.1));     // 5
console.log(Math.trunc(-4.9));   // -4

Look at the negative rows: floor goes toward a smaller number (more negative), while trunc simply removes the decimals. Also note that Math.round(-4.5) gives -4: halves are rounded up (toward the bigger number).

Handy memory trick:

  • Floor = the floor of a room is below you (go down).
  • Ceil = the ceiling is above you (go up).

A real use: pages needed for 25 items with 10 items per page.

const pages = Math.ceil(25 / 10);
console.log(pages);   // 3

Rounding to 2 decimals

const value = 2.34567;
console.log(Math.round(value * 100) / 100);   // 2.35

Multiply by 100, round, divide by 100 again. (Use 10 for one decimal, 1000 for three.)

Smallest and largest: min and max

console.log(Math.max(3, 9, 1));   // 9
console.log(Math.min(3, 9, 1));   // 1

To find the largest number in an array, use the spread syntax (...), which you will learn soon:

const scores = [72, 85, 90, 64];
console.log(Math.max(...scores));   // 90
console.log(Math.min(...scores));   // 64

Watch out for edge cases:

console.log(Math.max());          // -Infinity (no values given)
console.log(Math.max(1, NaN));    // NaN       (one bad value ruins it)

Other useful functions

console.log(Math.abs(-7.5));      // 7.5   (remove the minus sign)
console.log(Math.sqrt(16));       // 4     (square root)
console.log(Math.cbrt(27));       // 3     (cube root)
console.log(Math.pow(2, 5));      // 32    (same as 2 ** 5)
console.log(Math.sign(-3));       // -1    (-1, 0 or 1 depending on the sign)
console.log(Math.hypot(3, 4));    // 5     (length of the diagonal)

Random numbers

Math.random() gives a random decimal from 0 up to (but never including) 1:

console.log(Math.random());   // for example 0.7364521908

To get useful random numbers, scale and round it.

A random whole number from 0 to 9

console.log(Math.floor(Math.random() * 10));

A dice roll (1 to 6)

const dice = Math.floor(Math.random() * 6) + 1;
console.log(dice);

Any range: min to max (both included)

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

console.log(randomInt(1, 100));    // 1 to 100
console.log(randomInt(5, 10));     // 5 to 10

(Functions are covered in the next section. For now, treat this as a recipe you can copy.)

A 6-digit OTP-style number

const otp = Math.floor(100000 + Math.random() * 900000);
console.log(otp);   // for example 482910

Good to know: Math.random() is fine for games, quizzes and demos, but it is not secure. Never use it for passwords, tokens or real OTPs. Real applications use crypto.getRandomValues() or a server.

Real-life use cases

1. Add GST to a price

const price = 999;
const gstRate = 18;

const gstAmount = (price * gstRate) / 100;
const total = price + gstAmount;

console.log(`GST: ₹${gstAmount.toFixed(2)}`);     // "GST: ₹179.82"
console.log(`Total: ₹${total.toFixed(2)}`);       // "Total: ₹1178.82"

2. Calculate an average and a percentage

const marks = 72 + 85 + 90;
const average = marks / 3;

console.log(average.toFixed(1));            // "82.3"
console.log(Math.round((85 / 120) * 100) + "%");   // "71%"

3. Keep a value within limits (clamp)

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

console.log(clamp(150, 0, 100));   // 100
console.log(clamp(-5, 0, 100));    // 0
console.log(clamp(42, 0, 100));    // 42

This is useful for progress bars, volume controls and sliders.

4. Even or odd

const number = 14;
console.log(number % 2 === 0 ? "even" : "odd");   // "even"

5. Area of a circle

const radius = 5;
const area = Math.PI * radius ** 2;

console.log(area.toFixed(2));   // "78.54"

6. Temperature conversion

const celsius = 37;
const fahrenheit = (celsius * 9) / 5 + 32;

console.log(`${celsius}°C = ${fahrenheit}°F`);   // "37°C = 98.6°F"

7. Safely read a number typed by the user

const input = "45";
const value = Number(input);

if (input.trim() === "" || Number.isNaN(value)) {
  console.log("Please enter a valid number");
} else {
  console.log("Double:", value * 2);   // "Double: 90"
}

Remember that Number("") is 0, so check for empty text first.

Common mistakes

  • Comparing with NaN using ===. x === NaN is always false. Use Number.isNaN(x).
  • Using toFixed() and then treating the result as a number. It returns a string. Wrap it in Number().
  • Trusting 0.1 + 0.2 === 0.3. Round, or compare with a small difference.
  • Forgetting that Number("") is 0. An empty input does not become NaN.
  • Using parseInt for decimals. parseInt("3.9") is 3. Use parseFloat().
  • Parsing "1,000". Commas break parsing. Remove them first: Number("1,000".replaceAll(",", "")).
  • Mixing up floor and trunc on negative numbers. Math.floor(-4.5) is -5, while Math.trunc(-4.5) is -4.
  • Wrong random range. Math.floor(Math.random() * 6) gives 0 to 5. Add + 1 for a dice.
  • Passing an array directly to Math.max(). Math.max([1, 2]) is NaN. Use Math.max(...array).
  • Using the global isNaN(). It gives odd answers for text. Prefer Number.isNaN().

Practice

  1. Convert each text to a number in the editor and note the results: "25", "25.75", "25px", "", "abc". Try Number(), parseInt() and parseFloat(). Where do they differ?
  2. Write Math.round, Math.floor, Math.ceil and Math.trunc for the value 7.6 and -7.6. Predict first, then run.
  3. A shirt costs ₹1499 and has a 15% discount. Print the final price with 2 decimals.
  4. Print how many pages you need to show 47 items with 10 items per page.
  5. Roll two dice and print both results and their sum.
  6. Write a number between 1 and 50, and print whether it is even or odd.
  7. Find the highest and lowest values in [34, 78, 12, 90, 56] using Math.max() and Math.min() with spread.
  8. Read the text "12abc". Use Number.isNaN() to show an error with Number(), and print 12 using parseInt().
  9. Challenge: convert 98.6 °F to Celsius using (F - 32) * 5 / 9, and round it to 1 decimal.

Recap

  • JavaScript has one number type for integers and decimals. Use 1_000_000 and 1e6 to write big numbers easily.
  • Parse text with Number() (strict), parseInt() (whole numbers, reads until it fails) and parseFloat() (decimals). Give parseInt() a radix of 10.
  • NaN means “not a valid number”. It is never equal to itself. Check with Number.isNaN().
  • Division by zero gives Infinity. Check with Number.isFinite().
  • Decimals can be inexact (0.1 + 0.2). Round at the end, and count money in the smallest unit.
  • toFixed(n) formats decimals but returns a string. toLocaleString() formats for display with commas and currency.
  • Math gives you round, floor, ceil, trunc, max, min, abs, sqrt, pow and random.
  • Random range formula: Math.floor(Math.random() * (max - min + 1)) + min. It is not secure for passwords.
  • Next you will learn to make decisions in code with conditions: if, else, switch and the ternary operator.