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.
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()orparseFloat()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:
- Its type is
"number". (typeof NaNgives"number".) - 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 usecrypto.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
NaNusing===.x === NaNis alwaysfalse. UseNumber.isNaN(x). - Using
toFixed()and then treating the result as a number. It returns a string. Wrap it inNumber(). - Trusting
0.1 + 0.2 === 0.3. Round, or compare with a small difference. - Forgetting that
Number("")is0. An empty input does not becomeNaN. - Using
parseIntfor decimals.parseInt("3.9")is3. UseparseFloat(). - Parsing
"1,000". Commas break parsing. Remove them first:Number("1,000".replaceAll(",", "")). - Mixing up
floorandtruncon negative numbers.Math.floor(-4.5)is-5, whileMath.trunc(-4.5)is-4. - Wrong random range.
Math.floor(Math.random() * 6)gives 0 to 5. Add+ 1for a dice. - Passing an array directly to
Math.max().Math.max([1, 2])isNaN. UseMath.max(...array). - Using the global
isNaN(). It gives odd answers for text. PreferNumber.isNaN().
Practice
- Convert each text to a number in the editor and note the results:
"25","25.75","25px","","abc". TryNumber(),parseInt()andparseFloat(). Where do they differ? - Write
Math.round,Math.floor,Math.ceilandMath.truncfor the value7.6and-7.6. Predict first, then run. - A shirt costs ₹1499 and has a 15% discount. Print the final price with 2 decimals.
- Print how many pages you need to show
47items with10items per page. - Roll two dice and print both results and their sum.
- Write a number between
1and50, and print whether it is even or odd. - Find the highest and lowest values in
[34, 78, 12, 90, 56]usingMath.max()andMath.min()with spread. - Read the text
"12abc". UseNumber.isNaN()to show an error withNumber(), and print12usingparseInt(). - 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_000and1e6to write big numbers easily. - Parse text with
Number()(strict),parseInt()(whole numbers, reads until it fails) andparseFloat()(decimals). GiveparseInt()a radix of10. NaNmeans “not a valid number”. It is never equal to itself. Check withNumber.isNaN().- Division by zero gives
Infinity. Check withNumber.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.Mathgives youround,floor,ceil,trunc,max,min,abs,sqrt,powandrandom.- 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,switchand the ternary operator.