cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Number & Math in depth

Go deeper into JavaScript numbers: safe integers, numeric limits, exact checks, formatting, Math helpers, random-number traps, and modern precision tools.

By the end, you can
  • 01
    Know the safe zoneUse Number.EPSILON, safe-integer checks, and the real Number limits.
  • 02
    Choose exact testsPick Number.isNaN, Number.isFinite, Number.isInteger, and Number.isSafeInteger deliberately.
  • 03
    Use Math responsiblyFormat numbers, avoid random bias, and feature-detect new Math helpers.

Precision is a map, not a mystery

The Numbers & math lesson showed the famous 0.1 + 0.2 surprise, NaN, Infinity, rounding, parsing, and the basic Math object. This lesson keeps the same one JavaScript type—number—but zooms in until you can see the ruler marks.

A JavaScript Number is a double-precision floating-point value. That means it can represent a huge range, but not every integer or decimal in that range. Near 1 the marks are extremely close together; far away they spread out. Professional number code is mostly about knowing which question you are asking: “Is this finite?”, “Is this an exact integer?”, “How should I print it?”, or “Is this random choice fair?”

The short version

Use strict Number. checks for validation, Number.isSafeInteger for exact integer identity, scaled Number.EPSILON for tiny decimal comparisons, and Math.floor for unbiased integer buckets.

You will also see recent helpers such as Math.sumPrecise and Math.f16round. They are feature-detected in the browser after mount because older engines may not have them yet.

Number.EPSILON & safe integers

STEP THROUGH

Number.EPSILON is the gap between 1 and the next representable Number. Think of it as the width of the smallest ruler mark near 1. It is perfect for explaining why 0.1 + 0.2 can be “close enough” to 0.3, but because the ruler marks grow farther apart at large magnitudes, real comparison helpers scale the tolerance by the size of the values.

Real-life analogyEPSILON is a tiny ruler gap

Near 1, JavaScript’s number ruler has marks so close together that tiny decimal dust can be ignored. But the farther you move from zero, the wider the gaps become. Eventually you reach the last house number where every integer address still exists: Number.MAX_SAFE_INTEGER.

In real life: A ruler with tiny marks near 1
In JavaScript: Number.EPSILON, the next gap after 1
In real life: A city map that skips no houses downtown
In JavaScript: Safe integers up to Number.MAX_SAFE_INTEGER
In real life: A rural road where house numbers jump
In JavaScript: Unsafe integers beyond 2 ** 53 - 1

Where the analogy stops: The ruler marks are not the same width everywhere. Number.EPSILON is a near-1 fact, so scale it for larger values.

Step through the boundary. Notice that “integer” and “safe integer” are different ideas.

Walk past the last safe integer
Step 0 of 5Ready
Your turn: follow the blue line

Step through the boundary where integer arithmetic stops being safe, then compare a tiny decimal error with Number.EPSILON.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
console.log(maxSafe + 1);console.log(maxSafe + 2);console.log(Number.isSafeInteger(maxSafe + 1));console.log(Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON);
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
BigInt is the exact-integer escape hatch

When you truly need whole numbers beyond the safe range—large IDs, counters, or exact arithmetic—the BigInt lesson shows the separate bigint type. Do not silently store huge identifiers in Number and hope every digit survives.

MAX_VALUE, MIN_VALUE & Infinity

Safe integers answer “which whole-number addresses are reliable?” Number.MAX_VALUE and Number.MIN_VALUE answer a different question: “how large or tiny can a finite floating-point magnitude be?”

Real-life analogyMAX_VALUE is the roof; MIN_VALUE is a thin slice

The name MIN_VALUE is the trap. It is not the most negative Number. It is the thinnest positive slice JavaScript can cut above zero: 5e-324.

In real life: Top of the building
In JavaScript: Number.MAX_VALUE, the largest finite Number
In real life: A slice of paper just above the floor
In JavaScript: Number.MIN_VALUE, the smallest positive Number
In real life: Falling below the lobby
In JavaScript: Negative numbers, down to -Number.MAX_VALUE
In real life: Past the roof
In JavaScript: Infinity after overflow

Where the analogy stops: Buildings have a lowest basement. Number.MIN_VALUE is not that; it is positive and extremely close to zero.

Number limits that sound similar but are not
NameReal meaningUse it when
Number.MAX_SAFE_INTEGER9007199254740991, the last integer before gaps appearYou need exact integer identity
Number.MAX_VALUELargest finite floating-point magnitudeYou are guarding against overflow
Number.MIN_VALUESmallest positive value above zeroYou are discussing underflow or subnormal values
Infinity / -InfinityA Number value outside the finite rangeA calculation overflowed or division by zero produced an unbounded result

If a calculation becomes too large, JavaScript does not throw. It produces Infinity. That can be useful in algorithms, but for user-facing quantities—prices, distances, percentages—treat it as invalid data.

Number.isInteger, isSafeInteger, isNaN & isFinite

SORT

JavaScript has two families of NaN and finite checks. The old global functions convert their input first. The Number. methods do not. That difference is the whole story.

Coercing globals vs strict Number methods
InputisNaNNumber.isNaNisFiniteNumber.isFinite
"abc"truefalsefalsefalse
""falsefalsetruefalse
"42"falsefalsetruefalse
NaNtruetruefalsefalse
Infinityfalsefalsefalsefalse
nullfalsefalsetruefalse

Use global isNaN or isFinite only when you intentionally want Type conversion first. In validation code, convert explicitly with Number(input), then use strict checks. For whole numbers, decide whether you merely need “no fraction” (Number.isInteger) or a safe exact integer (Number.isSafeInteger).

Global isNaN or Number.isNaN?
  • isNaN("abc")
  • isFinite("")
  • Number.isNaN("abc")
  • Number.isFinite("42")
  • Number.isInteger(4.0)
  • Number.isSafeInteger(2 ** 53)
Try it yourself
0 of 6 correct

Sort each predicate by the family it belongs to. The explanations call out coercion and safety.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

toPrecision, toExponential & toString(radix)

INTERACTIVE

Formatting methods answer “how should this Number be written as text?” toPrecision(5) keeps five significant digits. toExponential(2) uses scientific notation with two digits after the decimal. toString(radix) writes the same quantity in another base, from binary (2) through hexadecimal (16) up to base 36.

Real-life analogyRadix is a different odometer

The car has gone the same distance no matter which odometer digits you use. Binary and hex are just compact ways to read the same quantity, especially when debugging bits, colors, and byte values.

In real life: Decimal odometer
In JavaScript: 255
In real life: Binary odometer
In JavaScript: 11111111 from (255).toString(2)
In real life: Hex odometer
In JavaScript: ff from (255).toString(16)

Where the analogy stops: Changing radix changes the text representation, not the stored Number. Floating-point limits still apply before you print.

Try the presets, especially 2 ** 53, 5e-324, and -0. The previous and next rows show the nearest representable neighbors: the real spacing of the Number ruler at that point.

Inspect one Number from every angle
Inspector questionsPop out in the code editor (opens in a new tab)JavaScript
const value = Number(input);Number.isInteger(value);Number.isSafeInteger(value);value.toPrecision(5);value.toExponential(2);value.toFixed(2);value.toString(2);value.toString(16);
Live result123.456
Number.isIntegerfalse
Number.isSafeIntegerfalse
toPrecision(5)123.46
toExponential(2)1.23e+2
toFixed(2)123.46
toString(2)1111011.0111010010111100011010100111111011111001110111
toString(16)7b.74bc6a7ef9dc
within EPSILON of an integerfalse
previous representable123.45599999999999
next representable123.45600000000002
Try it yourself

123.456 is outside the safe-integer yes-zone. Decimals are stored as the nearest binary floating-point value.

Everything in the table is computed by your browser from the current input. Long radix strings are shortened only for display.

Math: rounding, trigonometry, logs & hypot

STEP THROUGH

The Math object is a toolbox, not a class you instantiate. You already know basics like Math.max. Deeper work often uses four groups: rounding (round, floor, ceil, trunc), trigonometry (sin, cos, atan2), logarithms (log, log10, log2), and geometry helpers like hypot.

Trigonometry uses radians, not degrees. The helper below converts degrees to radians, then runs real Math calls. At 180°, Math.sin(Math.PI) gives 1.2246467991473532e-16, a tiny near-zero value.

Tour Math with one angle setting
Step 0 of 6Ready
Your turn: follow the blue line

Change the angle, then step through real Math calls. Watch for the almost-zero sine at 180°.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
const radians = degrees * Math.PI / 180;console.log(Math.sin(radians));console.log(Math.hypot(3, 4));console.log(Math.log10(1000));console.log(Math.log2(8));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Change line 1: angle in degrees

Changing the angle starts a fresh replay. The hypot and log lines stay the same.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Rounding names point in different directions

Math.floor moves toward -Infinity, Math.ceil toward Infinity, Math.trunc toward zero, and Math.round to the nearest integer with half cases moving toward +Infinity.

Math.random pitfalls

RUN IT

Math.random() returns a pseudo-random Number in the half-open range [0, 1). It is fine for games, visual variety, simulations, and demos. It is not cryptographically secure. For tokens, passwords, or hard-to-guess IDs, use Web Crypto APIs such as crypto.getRandomValues() or crypto.randomUUID(); the Web Crypto lesson covers that security mindset.

Two common bugs are biased integer generation and biased shuffling. Math.round(Math.random() * 6) gives uneven end buckets and includes 0. array.sort(() => Math.random() - 0.5) asks a sorting algorithm to use a comparator that changes its mind.

See random bias in your own run
Fair integer and Fisher–YatesPop out in the code editor (opens in a new tab)JavaScript
function randomInt(min, max) {  return Math.floor(Math.random() * (max - min + 1)) + min;} function shuffle(items) {  const copy = [...items];  for (let i = copy.length - 1; i > 0; i -= 1) {    const j = Math.floor(Math.random() * (i + 1));    [copy[i], copy[j]] = [copy[j], copy[i]];  }  return copy;}
Your runnot run yet

Biased round result: 0–6

00
10
20
30
40
50
60

Fair floor result: 1–6

10
20
30
40
50
60

sort(() => random - 0.5)

ABC0
ACB0
BAC0
BCA0
CAB0
CBA0

Fisher–Yates

ABC0
ACB0
BAC0
BCA0
CAB0
CBA0
Try it yourself

Click Run samples to create a real distribution in your browser. No random numbers are generated during server render.

The histograms are labeled “your run” because they use your browser’s Math.random() when you click. Do not use Math.random() for secrets.

Math.sumPrecise, fround, f16round, clz32 & imul

FEATURE DETECT

Some Math helpers exist for precision or low-level interop. Math.fround rounds a Number to the nearest 32-bit floating-point value; Math.fround(5.5) is 5.5, while Math.fround(5.05) is 5.050000190734863. Math.clz32(1) returns 31 because a 32-bit view of 1 has thirty-one leading zero bits. Math.imul(0xffffffff, 5) returns -5 because it multiplies as signed 32-bit integers.

Math.sumPrecise and Math.f16round are newer. This page checks for them in the browser after mount. When sumPrecise is absent, compare the documented purpose with the naive sum shown below: [1e16, 1, -1e16] loses the 1 when added naively. When f16round is absent, the page describes it as rounding to half precision rather than pretending to run it.

Step through specialized Math helpers
Step 0 of 5Ready
Your turn: follow the blue line

These helpers are specialized: float32 rounding, bit operations, and feature-detected new Math methods.

Running in
  1. script
Next: line 1
Click the blue line to take the next stepPop out in the code editor (opens in a new tab)JavaScript
console.log(Math.fround(5.05));console.log(Math.clz32(1));console.log(Math.imul(0xffffffff, 5));console.log(typeof Math.sumPrecise === "function");
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Feature-detect newest Math methods
Always-available helper checksPop out in the code editor (opens in a new tab)JavaScript
console.log(Math.fround(5.5));console.log(Math.fround(5.05));console.log(Math.clz32(1));console.log(Math.imul(0xffffffff, 5));console.log(typeof Math.sumPrecise === "function");
Browser feature detectionwaiting
Naive [1e16, 1, -1e16] sum…
Math.sumPrecise available?…
sumPrecise resultnot available here
Math.f16round available?…
f16round(1.337)rounds to half precision when available
Reference note5.050000190734863 is float32, not half precision
Try it yourself
Detected after mount

Waiting for the browser before checking optional Math methods.

Math.sumPrecise and Math.f16round are recent. Older browsers and Node 22 may not have them.

Where you’ll use this

Number depth shows up in ordinary frontend work:

  • Validate form input with Number.isFinite after intentional conversion, so "" does not sneak in as zero.
  • Check Number.isSafeInteger(id) before treating numeric IDs as exact. Use BigInt or strings for identifiers beyond the safe range.
  • Use toString(16) and toString(2) when inspecting colors, flags, masks, and byte values.
  • Use Math.hypot(dx, dy) for pointer distance, canvas geometry, and drag thresholds.
  • Use Fisher–Yates for quizzes, flashcards, and playlists; avoid random sort comparators.
Which method fits the job?
  • value.toPrecision(5)
  • value.toString(16)
  • Math.ceil(price)
  • Math.floor(Math.random() * n)
  • Fisher–Yates shuffle
  • Math.imul(hash, 31)
Try it yourself
0 of 6 correct

Sort each tool by the job it is best suited for.

Choose a category for every card. You can change an answer at any time; Reset clears them all.

Common misconceptions

“MIN_VALUE is the most negative number.”

No. It is the smallest positive Number. The most negative finite Number is -Number.MAX_VALUE.

“If a value is an integer, it is safe.”

Number.isInteger(2 ** 53) is true, but Number.isSafeInteger(2 ** 53) is false.

“Number.EPSILON fixes every decimal comparison.”

It is the gap near 1. Scale your tolerance for larger magnitudes.

“The global checks are stricter because they are shorter.”

The opposite: isNaN and isFinite coerce first. Number.isNaN and Number.isFinite are strict.

“Math.random is fair and secure for everything.”

It is neither cryptographically secure nor automatically unbiased after you transform it.

Practice: precision and Math

5 EXERCISES
Exercise 1 · Warm-upPredict four number checks

Predict the four console lines without running the code, then check your answer.

Starter codePop out in the code editor (opens in a new tab)JavaScript
console.log(Number.isSafeInteger(2 ** 53));
console.log(Number.isFinite("42"));
console.log(isFinite("42"));
console.log((255).toString(16));

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeWrite isAlmostEqual(a, b)

    Write a helper that treats tiny floating-point dust as equal, then test 0.1 + 0.2 against 0.3.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function isAlmostEqual(a, b) {
      return Math.abs(a - b) <= Number.EPSILON * Math.max(1, Math.abs(a), Math.abs(b));
    }
    console.log(isAlmostEqual(0.1 + 0.2, 0.3));

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeGenerate a fair random integer

      Fill in a helper that returns an integer from min through max, inclusive. Which rounding method belongs in it?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function randomInt(min, max) {
        return Math.floor(Math.random() * (max - min + 1)) + min;
      }

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · ChallengeImplement Fisher–Yates

        Write the shuffle shown in the lesson. The important correctness property is not that one run looks mixed; it is that the result keeps the same items exactly once.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        function shuffle(items) {
          const copy = [...items];
          for (let i = copy.length - 1; i > 0; i -= 1) {
            const j = Math.floor(Math.random() * (i + 1));
            [copy[i], copy[j]] = [copy[j], copy[i]];
          }
          return copy;
        }

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · PracticeRead one number in two bases

          Use toString(radix) to print 255 in binary and hexadecimal.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          const value = 255;
          console.log(value.toString(2));
          console.log(value.toString(16));

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            Every code answer is based on real JavaScript output. Read the explanations for the wrong answers too.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does the unsafe integer equality print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2);

              Choose an answer to see the explanation.

            2. Question 2 of 7What is Number.MIN_VALUE?

              Choose an answer to see the explanation.

            3. Question 3 of 7What do the strict and global NaN checks print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(Number.isNaN("abc"));
              console.log(isNaN("abc"));

              Choose an answer to see the explanation.

            4. Question 4 of 7What does decimal ten print in radix 2?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log((10).toString(2));

              Choose an answer to see the explanation.

            5. Question 5 of 7What does the sine of JavaScript's PI print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(Math.sin(Math.PI));

              Choose an answer to see the explanation.

            6. Question 6 of 7Which expression gives an unbiased die roll from 1 through 6?

              Choose an answer to see the explanation.

            7. Question 7 of 7What do fround, clz32, and imul print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(Math.fround(5.05));
              console.log(Math.clz32(1));
              console.log(Math.imul(0xffffffff, 5));

              Choose an answer to see the explanation.

            Key takeaways

            • Number.EPSILON is the gap near 1; scale it when comparing larger values.
            • Number.MAX_SAFE_INTEGER is about exact integer identity; Number.MAX_VALUE and Number.MIN_VALUE are floating-point magnitude limits.
            • Prefer strict Number. predicates unless you intentionally want coercion.
            • toPrecision, toExponential, and toString(radix) print the same Number with different rules.
            • Math.random() is not secure, and transformations can introduce bias.
            • Feature-detect recent helpers such as Math.sumPrecise and Math.f16round.

            Remember the one-liner.
            A JavaScript Number is a wide but spaced-out ruler: know the gap, check the range, and choose the right Math tool.

            Up next: Internationalization with Intl — formatting numbers for real readers, currencies, locales, and units.

            CompleteFrontend Clear concepts. Working examples.