Number Toolbox 0/7

JavaScript basicsNumbers in plain wordsOne tool at a time

Number
Toolbox

JavaScript has one main number type for whole numbers and decimals alike. This guide shows how to check numbers, turn text into numbers, round them, do maths, avoid decimal surprises and show them nicely as money, with a small example for each that you can run.

JavaScript ES202421 tools
01

Make and check

Write numbers, meet the special values NaN and Infinity, and test what kind of number you have.

Start hereNaNInfinityisIntegerMust know

In JavaScript, 7 and 7.5 are the same type: number. There are also a few special values. Infinity is what you get past the biggest number, and NaN, short for "not a number", is the answer to maths that makes no sense.

make.jsJAVASCRIPT
const price = 450;
const rate = 7.5;
const big = 1_000_000;          // underscores only help you read it
const tiny = 2.5e-3;            // 0.0025 in science notation

console.log(typeof price, typeof rate);  // whole or decimal, both are "number"
console.log(big, tiny);
console.log(10 / 0, -10 / 0);            // dividing by zero gives Infinity
console.log(0 / 0, "abc" * 2);           // NaN means "not a number"

Easy way to remember: NaN is still of type number. It just means the maths went wrong somewhere earlier.

Terminal OUTPUT
$ node make.js
number number
1000000 0.0025
Infinity -Infinity
NaN NaN
Number.isInteger(n)

Checks for a whole number with no decimals.

See the example
Gives true or falseOnly reads
Number.isFinite(n)

Checks for a real, countable number. Not NaN, not Infinity.

See the example
Gives true or falseOnly reads
Number.isNaN(n)

Checks for NaN without converting first.

See the example
Gives true or falseOnly reads
isNaN(x)

The older check. It converts text first, so "hello" counts.

See the example
Gives true or falseOnly reads
check.jsJAVASCRIPT
console.log(Number.isInteger(5), Number.isInteger(5.5));
console.log(Number.isFinite(42), Number.isFinite(Infinity));

// NaN is the only value that is not equal to itself
console.log(NaN === NaN);
console.log(Number.isNaN(NaN));        // the reliable check
console.log(isNaN("hello"));           // older isNaN converts first: true
console.log(Number.isNaN("hello"));    // Number.isNaN does not: false

Why it matters: NaN is never equal to anything, not even itself, so x === NaN is always false. Use Number.isNaN(x).

Terminal OUTPUT
$ node check.js
true false
true false
false
true
true
false
02

Text to number

Turn what a person typed into a real number, and catch it when they typed something else.

ConvertingNumberparseIntparseFloat
InputNumber(x)parseInt(x, 10)parseFloat(x)
"42"424242
"4.5"4.544.5
"42px"NaN4242
""0NaNNaN
"abc"NaNNaNNaN
Number(x)

Converts the whole value. Any junk gives NaN.

See the example
Gives a number or NaNMakes a new one
parseInt(text, base)

Reads a whole number from the start, stopping at junk. Always pass 10.

See the example
Gives a number or NaNMakes a new one
parseFloat(text)

Reads a decimal number from the start.

See the example
Gives a number or NaNMakes a new one
+x

A short way to write Number(x).

See the example
Gives a number or NaNMakes a new one
parse.jsJAVASCRIPT
console.log(Number("42"), Number("4.5"), Number(""));  // empty text becomes 0
console.log(Number("42px"));                  // any junk gives NaN

console.log(parseInt("42px", 10));            // reads digits until it hits junk
console.log(parseInt("08", 10), parseInt("ff", 16)); // always pass the base
console.log(parseFloat("3.14 metres"));
console.log(+"7" + 1, "7" + 1);               // + in front converts; + between joins text

const qty = Number("abc");
console.log(Number.isNaN(qty) ? "please enter a number" : qty);

Rule of thumb: use Number for form fields, since it rejects junk. Use parseInt or parseFloat only when you expect units like "px" on the end.

Terminal OUTPUT
$ node parse.js
42 4.5 0
NaN
42
8 255
3.14
8 71
please enter a number
03

Round it

Round up, round down, cut off decimals, or show a fixed number of decimal places.

RoundingMath.roundtoFixed
Valueroundfloorceiltrunc
4.5675454
4.55454
-4.5-4-5-4-4
Math.round(n)

To the nearest whole number. Halves go up.

See the example
Gives a numberMakes a new one
Math.floor(n)

Always down, towards minus infinity.

See the example
Gives a numberMakes a new one
Math.ceil(n)

Always up.

See the example
Gives a numberMakes a new one
Math.trunc(n)

Just cuts the decimals off.

See the example
Gives a numberMakes a new one
toFixed(digits)

Rounds to that many decimals for display.

See the example
Gives a stringMakes a new one
round.jsJAVASCRIPT
const n = 4.567;

console.log(Math.round(n), Math.floor(n), Math.ceil(n), Math.trunc(n));
console.log(Math.floor(-4.5), Math.trunc(-4.5));   // floor goes down, trunc cuts off

console.log(n.toFixed(2));           // "4.57": a string with 2 decimals
console.log(n.toFixed(0), typeof n.toFixed(2));
console.log(Number(n.toFixed(1)));   // back to a number

console.log((1234.5678).toPrecision(3)); // 3 significant digits

Watch for this: toFixed gives you text, not a number. Wrap it in Number() if you need to keep calculating.

Terminal OUTPUT
$ node round.js
5 4 5 4
-5 -4
4.57
5 string
4.6
1.23e+3
04

Math toolbox

Find the biggest and smallest, powers and roots, remainders and random numbers.

MathsMath.max%Math.random
Math.max / Math.min(...nums)

Picks the biggest or smallest. Spread an array into it.

See the example
Gives a numberOnly reads
Math.abs(n)

Removes the minus sign.

See the example
Gives a numberMakes a new one
a ** b

a to the power of b.

See the example
Gives a numberMakes a new one
Math.sqrt(n)

The square root.

See the example
Gives a numberMakes a new one
a % b

The remainder after dividing. Great for even or odd checks.

See the example
Gives a numberMakes a new one
Math.random()

A random decimal from 0 up to, not including, 1.

See the example
Gives a numberMakes a new one
math.jsJAVASCRIPT
console.log(Math.max(3, 9, 1), Math.min(3, 9, 1));
console.log(Math.max(...[40, 75, 12]));      // spread an array in
console.log(Math.abs(-8), 2 ** 10, Math.sqrt(81));
console.log(17 % 5, 10 % 2 === 0);           // remainder; checks even numbers

// a whole random number between min and max, both included
const randomInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
const roll = randomInt(1, 6);
console.log(roll >= 1 && roll <= 6);

The pattern: for a random whole number between min and max, scale random, floor it, then shift it up by min.

Terminal OUTPUT
$ node math.js
9 1
75
8 1024 9
2 true
true
05

Decimal gotchas

Understand why 0.1 + 0.2 is not 0.3, handle money safely and use BigInt for huge whole numbers.

AccuracyEPSILONBigIntMust know

Computers store decimals in binary, and some simple decimals like 0.1 cannot be stored exactly, the same way 1/3 never ends in decimal. The error is tiny, but it shows up when you compare.

ProblemFix
Comparing decimalscheck the gap is below Number.EPSILON
Adding moneycount whole paise or cents, divide only for display
Whole numbers above 9 quadrillionuse BigInt, written with an n on the end
gotchas.jsJAVASCRIPT
console.log(0.1 + 0.2);                  // tiny error from how decimals are stored
console.log(0.1 + 0.2 === 0.3);

const close = (a, b) => Math.abs(a - b) < Number.EPSILON;
console.log(close(0.1 + 0.2, 0.3));     // compare with a tiny allowed gap

// for money, count the smallest unit (paise) as whole numbers
const paise = 10 + 20;                  // ₹0.10 + ₹0.20
console.log(paise / 100);

console.log(Number.MAX_SAFE_INTEGER);
console.log(9007199254740993);           // too big: the last digit is lost
console.log(9007199254740993n + 1n);     // BigInt, with n, stays exact

Rule of thumb: never store money as rupees with decimals. Store paise as a whole number and format it at the very end.

Terminal OUTPUT
$ node gotchas.js
0.30000000000000004
false
true
0.3
9007199254740991
9007199254740992
9007199254740994n
06

Show it nicely

Format numbers for people: thousands separators, currency, percent and short forms like 2.4M.

FormattingtoLocaleStringIntl.NumberFormat

Picture it: formatting

1234567.891Intl.NumberFormat("en-IN", { currency })₹12,34,567.89The number stays the same. Only how it looks changes.
toLocaleString(locale)

Adds separators the way that country writes numbers.

See the example
Gives a stringMakes a new one
Intl.NumberFormat(locale, options)

Builds a reusable formatter for currency, percent or compact numbers.

See the example
Gives a formatterMakes a new one
format.jsJAVASCRIPT
const amount = 1234567.891;

console.log(amount.toLocaleString("en-IN"));   // Indian grouping: lakhs and crores
console.log(amount.toLocaleString("en-US"));

const inr = new Intl.NumberFormat("en-IN", { style: "currency", currency: "INR" });
console.log(inr.format(amount));

const usd = new Intl.NumberFormat("en-US", { style: "currency", currency: "USD" });
console.log(usd.format(amount));

const pct = new Intl.NumberFormat("en-IN", { style: "percent", maximumFractionDigits: 1 });
console.log(pct.format(0.1834));

const short = new Intl.NumberFormat("en-US", { notation: "compact" });
console.log(short.format(1500), short.format(2_400_000));

Why it matters: en-IN groups by lakhs and crores while en-US groups by thousands. Make the formatter once and call format as often as you like.

Terminal OUTPUT
$ node format.js
12,34,567.891
1,234,567.891
₹12,34,567.89
$1,234,567.89
18.3%
1.5K 2.4M
07

All together

Split a restaurant bill with tax between friends, down to the last paisa.

Putting it togetherMath.round%Intl

Splitting ₹859.43 three ways does not divide evenly. This example works in whole paise so nothing gets lost, then hands the leftover paise to the first people so the shares still add up to the total.

bill.jsJAVASCRIPT
// split a restaurant bill fairly, working in paise so nothing is lost
const items = [
  { name: "Paneer tikka", price: 349.0 },
  { name: "Dal makhani", price: 289.5 },
  { name: "Naan x4", price: 180.0 },
];
const people = 3;
const GST = 0.05;

const toPaise = (rupees) => Math.round(rupees * 100);
const subtotal = items.reduce((sum, item) => sum + toPaise(item.price), 0);
const tax = Math.round(subtotal * GST);
const total = subtotal + tax;

// share out the paise, and give any leftover to the first people
const base = Math.floor(total / people);
const leftover = total % people;
const shares = Array.from({ length: people }, (_, i) => base + (i < leftover ? 1 : 0));

const inr = new Intl.NumberFormat("en-IN", { style: "currency", currency: "INR" });
console.log("total", inr.format(total / 100));
console.log(shares.map((p) => inr.format(p / 100)).join(" | "));
console.log("adds up:", shares.reduce((a, b) => a + b) === total);

What each part uses: whole paise from module 05, Math.round and Math.floor from 03, the remainder operator from 04, and Intl.NumberFormat from 06.

Terminal OUTPUT
$ node bill.js
total ₹859.43
₹286.48 | ₹286.48 | ₹286.47
adds up: true
TerminalBASH
# save any example as a file and run it with Node 22
$ node bill.js
# or paste it into your browser console with F12

Which one do I need?

Start from what you want to do, then read across to the tool and what it gives back.

I want toUseYou get
Check for a whole numberNumber.isInteger(n)true or false
Check for NaNNumber.isNaN(n)true or false
Turn text into a numberNumber(text)a number or NaN
Read "42px" as 42parseInt(text, 10)a number
Round to nearestMath.round(n)a whole number
Show 2 decimalsn.toFixed(2)a string
Find the biggestMath.max(...list)a number
Check even or oddn % 2 === 0true or false
Random from 1 to 6Math.floor(Math.random() * 6) + 1a whole number
Compare decimalsMath.abs(a - b) < Number.EPSILONtrue or false
Huge exact numbers123na BigInt
Show as rupeesIntl.NumberFormat("en-IN", { style: "currency", currency: "INR" })a formatter