Skip to main content

Command Palette

Search for a command to run...

Numbers in JavaScript + (BigInt)

Updated
9 min readView as Markdown
Numbers in JavaScript + (BigInt)
G

Hello! I'm a dedicated software developer with a passion for coding and a belief in technology's impact on our world. My programming journey started a few years ago and has reshaped my career and mindset. I love tackling complex problems and creating efficient code. My skills cover various languages and technologies like JavaScript, Angular, ReactJS, NodeJs, and Go Lang. I stay updated on industry trends and enjoy learning new tools. Outside of coding, I cherish small routines that enhance my workday, like sipping tea, which fuels my creativity and concentration. Whether debugging or brainstorming, it helps me focus. When I'm not coding, I engage with fellow developers. I value teamwork and enjoy mentoring newcomers and sharing my knowledge to help them grow. Additionally, I explore the blend of technology and creativity through projects that incorporate art and data visualization. This keeps my perspective fresh and my passion alive. I'm always seeking new challenges, from open-source contributions to hackathons and exploring AI. Software development is more than a job for me—it's a passion that drives continuous learning and innovation.

"Last updated: September 2026"

To represent numeric value in javascript we need to use numbers.
As I mentioned in my previous article(Types Values and variables in Javascript) we need to use specific data types to store specific values.

In our case, if we want to store some numeric value we need to use a number data type.

JavaScript represents numbers using the 64-bit floating-point format defined by the IEEE 754 standard.

The JavaScript number format allows us to represent all numeric values between, -9,007,199,254,740,992 (-2⁵³) and 9,007,199,254,740,992 (2⁵³).
If we use values larger than this we may lose precision in trailing digits.

If a number appears directly in a JavaScript program, it called numeric literals.
JavaScript supports numeric literals in several formats.
Let’s look into it one by one.

Integer Literals

In the JavaScript program, we can use the sequence on digits from 0 to 9, to represent any base-10 numeric values.

Examples:-

5
88
56
555986547

JavaScript also allows us to use hexadecimal values(base-16). Hexadecimal literals are represented by adding 0x or 0X as a prefix to that number.
It uses 0 to 9 or a(or A) to f(or F) witch represents values from 10 to 15.

Examples:-

0xfca99       // => 1034905 = (15 × 16⁴) + (12 × 16³) + (10 × 16²) + (9 × 16¹) + (9 × 16⁰)
8873          // => 34931 = (8 × 16³) + (8 × 16²) + (7 × 16¹) + (3 × 16⁰)

In ES6 and later, we can also represent integers in binary(base-2) or octal(base-8) using prefixes 0b and 0o(or 0B and 0O) respectively.

Examples:-

0b110110110        // => (1 × 2⁸) + (1 × 2⁷) + (0 × 2⁶) + (1 × 2⁵) + (1 × 2⁴) + (0 × 2³) + (1 × 2²) + (1 × 2¹) + (0 × 2⁰)
0o57246            // => (5 × 8⁴) + (7 × 8³) + (2 × 8²) + (4 × 8¹) + (6 × 8⁰)

Floating Point literals

Floating-point literals can have decimal point.
A real value is represented as an integral part of the number, followed by a decimal point and fractional part of the number.

Floating-point literals can also be represented using exponential notation.
A real number followed by letter e(or E) with optional +/- sign, followed by an integer exponent.

This notation represents a real number multiplied by 10 to the power of the exponent.

Examples:-

3.14
55482.2287
7.9985e33     // => 7.9985 × 10²³
1.221533E-11  // => 1.221533 × 10⁻¹¹

Note:-

We can use separators in numeric literals to make them easier to read.

Long numbers are hard to read, so ES2021 added underscore separators. They are ignored by the engine and exist purely for our eyes:

const budget = 1_000_000;
console.log(budget);  // 1000000
 
const bytes = 0xFF_FF_FF;
console.log(bytes);   // 16777215

One catch — they only work in numeric literals in our source code. A string does not get the same treatment:

console.log(Number("1_000"));  // NaN

So they are for numbers we type, not numbers that arrive from an input or an API.

Why 0.1 + 0.2 is not 0.3

Run this and JavaScript will look broken:

console.log(0.1 + 0.2);          // 0.30000000000000004
console.log(0.1 + 0.2 === 0.3);  // false

It is not broken, and it is not a JavaScript problem — Python, Java and C do exactly the same thing. Every number in JavaScript is a 64-bit binary float, and 0.1 cannot be represented exactly in binary, in the same way 1/3 cannot be written exactly in decimal. We store the closest available value, and the tiny errors add up.

So do not compare floats with ===. Compare the difference against a tolerance:

console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);  // true

Number.EPSILON is the smallest gap between 1 and the next representable number — a reasonable tolerance for small values.

For money, do not use floats at all. Store the smallest unit as an integer — paise instead of rupees, cents instead of dollars — and divide only when displaying:

const priceInPaise = 19999;                    // ₹199.99
const totalInPaise = priceInPaise * 3;
console.log(totalInPaise / 100);               // 599.97

Every rounding error in a billing system I have seen started with someone storing 199.99 in a float.

The safe integer range

Floats also limit how large an integer can go before it stops being exact:

console.log(Number.MAX_SAFE_INTEGER);      // 9007199254740991
console.log(Number.MAX_SAFE_INTEGER + 1);  // 9007199254740992
console.log(Number.MAX_SAFE_INTEGER + 2);  // 9007199254740992  <-- same answer

No error, just a wrong number. Past that limit, integers need BigInt — which we covered in the types post.

Arithmetic in JavaScript

JavaScript program works with numbers using arithmetic operators, that language provides.
These includes *+, -, , /, and %.

%(Modulo) is used to get a remainder after division.

ES2016 adds ** for exponentiation.

Examples:-

20**4 // => 160000

Arithmetic in JavaScript does not raise an error in case of overflow, underflow, or division by zero.
When the number(or a result of the operation) is larger than the largest representable number(overflow), the resulting value is a special infinite value, Infinity.

Similarly, if the number(or a result of the operation) is smaller than the smallest representable value, the resulting special value is negative infinity, -Infinity.

The zero divide by zero does not have a well-defined value and the result of this operation is a special not-a-number value(NaN).

Checking for NaN

NaN is the only value in JavaScript that is not equal to itself:

console.log(NaN === NaN);  // false

Which means === is useless for detecting it. There are two working checks, and one of them is a trap:

console.log(isNaN("hello"));         // true  <-- converts the string first, then checks
console.log(Number.isNaN("hello"));  // false <-- "hello" is a string, not NaN
 
console.log(Number.isNaN(NaN));      // true
console.log(Object.is(NaN, NaN));    // true

The global isNaN() converts its argument to a number before checking, so it really answers "is this not a number?" rather than "is this NaN?". Number.isNaN() (ES6) does what the name says. Use that one.

parseInt, Number(), and the radix

These two look interchangeable and are not:

console.log(parseInt("12px"));  // 12  — reads until it hits something invalid
console.log(Number("12px"));    // NaN — the whole string must be a valid number

parseInt is forgiving, which is useful for reading CSS values and dangerous for validating user input. If a field must contain a number, Number() is the stricter check.

Always pass the radix as the second argument:

console.log(parseInt("0x1F"));      // 31  — guessed hexadecimal
console.log(parseInt("0x1F", 10));  // 0   — read as decimal, stops at the "x"
console.log(parseInt("08", 10));    // 8

Number.parseInt and Number.parseFloat (ES6) are the exact same functions, just moved onto Number so they are not floating around as globals. Either works.

toFixed and its rounding surprise

toFixed is the usual way to cut a number to a fixed number of decimals. Two things about it catch people out.

First, it returns a string:

console.log(typeof (5).toFixed(2));  // "string"
console.log((5).toFixed(2) + 1);     // "5.001"  — string concatenation, not addition

Second, its rounding does not always match what you were taught in school:

console.log((2.5).toFixed(0));    // "3"
console.log((1.5).toFixed(0));    // "2"
console.log((1.005).toFixed(2));  // "1.00"   <-- not "1.01"

That last one is the floating-point problem again. 1.005 is actually stored as something very slightly below 1.005, so rounding it down is technically correct. Which is another reason not to do money arithmetic in floats.

Intl.NumberFormat for anything a user sees

For currency, percentages and thousand separators, do not hand-roll it. Intl.NumberFormat handles the locale rules for you — including Indian grouping, which is 2-2-3, not 3-3-3:

const inr = new Intl.NumberFormat("en-IN", {
  style: "currency",
  currency: "INR",
});
 
console.log(inr.format(1234567.891));  // ₹12,34,567.89

Notice the grouping: 12,34,567, not 1,234,567. Writing that by hand with a regex is exactly the kind of thing that works in testing and breaks for half your users.

console.log(new Intl.NumberFormat("en-IN").format(1234567));                       // 12,34,567
console.log(new Intl.NumberFormat("en-US", { notation: "compact" }).format(1234567)); // 1.2M

The Math object

Math is a plain object of number utilities. It is not a constructor — there is no new Math().

The ones worth knowing:

Math.round(4.5);    // 5   — nearest, .5 rounds up
Math.floor(4.9);    // 4   — always down
Math.ceil(4.1);     // 5   — always up
Math.trunc(-4.9);   // -4  — just drops the decimals
Math.floor(-4.9);   // -5  — note the difference from trunc for negatives
 
Math.abs(-7);       // 7
Math.max(3, 9, 1);  // 9
Math.min(3, 9, 1);  // 1
Math.sqrt(16);      // 4
Math.pow(2, 10);    // 1024   — or just 2 ** 10
Math.random();      // 0 to (but not including) 1

Math.max takes separate arguments, not an array, so spread it:

const scores = [42, 91, 7];
console.log(Math.max(...scores));  // 91

A random integer in a range comes up often enough to memorise:

function randomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
 
console.log(randomInt(1, 6));  // a dice roll

One warning: Math.random() is not cryptographically secure. For tokens, passwords or anything a user should not be able to predict, use crypto.getRandomValues().

Date and Time

There is one more number-adjacent topic: dates. Internally a Date is just a number — milliseconds since 1 January 1970 UTC:

console.log(Date.now());  // e.g. 1789200000000

But the Date API around that number has been a source of complaints for as long as JavaScript has existed — months counted from zero, mutable objects, no real timezone support. It finally has a replacement: the Temporal API, which reached browsers in 2026.

Dates deserve their own post rather than a paragraph here, so we will cover both properly later in this series.

That’s all I wanted to cover about Numbers data type in JavaScript. In an upcoming article in this series, I will cover the Text data type of JavaScript in detail.

Hope you like it, if yes **like & share.**

Thanks for your time.

Happy coding….

← Types, values, and variables in JavaScript JavaScript Strings →*

JavaScript - Basics to Advance

Part 4 of 12

This series will cover everything you need to know about JavaScript from basics to advanced. Please stick with us and take your JS code quality and productivity to another level #JavaScript #JS

Up next

JavaScript Strings

Last updated: September 2026 — added replaceAll, at(), tagged templates, String.raw, and a section on why .length lies. Every programming language has a set of data types that they support. JavaScript

More from this blog

H

Hacker's Haven

28 posts

I'm a Senior Software Developer with expertise in programming languages and tech. Follow me for detailed articles and tutorials on software development tools and frameworks.