cf.completefrontendCode editorOpen lab
THE JAVASCRIPT FIELD GUIDE

Numbers & math

Learn how JavaScript represents integers and decimals, why 0.1 + 0.2 is not exactly 0.3, and how to use rounding, parsing, Math, and numeric separators safely.

By the end, you can
  • 01
    Explain decimal surprisesUse IEEE 754 intuition and Number.EPSILON for tiny floating-point errors.
  • 02
    Handle special valuesRecognize NaN, Infinity, and -0 without being fooled by coercion.
  • 03
    Use number toolsRound, parse, call Math, and write readable numeric literals.

Numbers are one type

JavaScript has one everyday number type: number. It holds whole numbers like 7, decimals like 3.14, and a few special values you will meet soon. The Data types lesson already gave away one odd fact: typeof NaN is "number". This lesson explains why that is not a typo.

Numbers show up everywhere: prices, animation positions, form inputs, page counts, timers, chart values, and random choices. Most of the time they feel like calculator numbers. But JavaScript stores them as 64-bit floating-point values, so some decimals are tiny approximations instead of exact values.

Real-life analogyDecimals are like measuring cups

A measuring cup has printed marks. If the amount you want lands between two marks, you choose the nearest one. JavaScript numbers work similarly: they choose the nearest representable value.

In real life: A cup can show 1/2 exactly
In JavaScript: Binary can store 0.5 exactly
In real life: A cup may need a mark between printed ticks
In JavaScript: Some decimals land between representable Numbers
In real life: You round for the recipe
In JavaScript: You round for display with toFixed or compare with a tolerance

Where the analogy stops: A measuring cup is visibly imprecise. JavaScript's approximations are usually so tiny that you only notice them in equality checks or many repeated calculations.

We will keep arithmetic operators like +, -, *, /, %, and precedence light here because the next module starts with Arithmetic & assignment. We will also only tease BigInt, Type conversion, Number & Math in depth, and Internationalization with Intl; each gets its own lesson later.

Floating point: why 0.1 + 0.2 is not exactly 0.3

INTERACTIVE

JavaScript numbers follow the IEEE 754 double-precision format. A friendly way to picture it is: one bit for the sign, some bits for the size of the number, and the rest for the significant digits. You do not need to memorize the layout yet. The important idea is that there are many numbers, but only finitely many bit patterns, so some values are represented by their nearest neighbor.

Real-life analogyBinary decimals are like writing 1/3 in decimal

In decimal, 1 / 3 becomes 0.3333… forever. You must stop writing somewhere, so a tiny error remains. Binary has the same problem with values like 0.1.

In real life: Decimal cannot finish 1/3: 0.3333…
In JavaScript: Binary cannot finish 0.1 exactly
In real life: You stop writing after enough digits
In JavaScript: IEEE 754 stores a nearest finite bit pattern
In real life: The rounded value is close enough for many recipes
In JavaScript: The stored value is close enough for most UI work

Where the analogy stops: This analogy is about representation, not base-ten display. JavaScript still prints friendly decimal strings most of the time so you are not staring at the stored bits.

Explore decimal sums
The classic decimal surprisePop out in the code editor (opens in a new tab)JavaScript
const left = 0.1;const right = 0.2;const sum = left + right;const expected = 0.3;console.log(sum);console.log(sum === expected);console.log(sum.toFixed(2));console.log(sum.toPrecision(20));console.log(Math.abs(sum - expected) < Number.EPSILON);
Live result0.1 + 0.2
real sum0.30000000000000004
expected0.3
sum === expectedfalse
sum.toFixed(2)0.30
sum.toPrecision(20)0.30000000000000004441
within EPSILONtrue
Try it yourself

The real sum is extremely close, but not exactly equal. Use a tolerance or round for display instead of expecting exact decimal equality.

The code block shows the classic 0.1 + 0.2 case. The controls run the same checks with other decimal pairs.

The surprise is not that JavaScript is bad at math. It is that base 2 and base 10 have different easy fractions. 0.5 and 0.25 are exact because they are halves and quarters. 0.1 is not exact, so 0.1 + 0.2 lands at the nearest representable number, 0.30000000000000004.

Safe integers

Whole numbers are exact up to Number.MAX_SAFE_INTEGER, which is 9007199254740991. Above that, JavaScript cannot represent every neighboring integer. The BigInt lesson will show the n suffix for integers beyond that limit.

Exact or approximate?
  • 0.5 + 0.25
  • 0.1 + 0.2
  • 2 ** 53 + 1
  • 1000000 * 3
  • 0.1 * 3
  • 9007199254740991
Try it yourself
0 of 6 correct

Sort each expression by whether JavaScript can represent the result exactly as a Number in normal use.

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

NaN, Infinity & -0

STEP THROUGH

Numbers include a few values that are not ordinary points on a number line. NaN means “not a valid numeric answer.” Infinity and -Infinity are what you get when a calculation overflows the normal range or divides by zero. Negative zero is a real sign bit attached to zero.

Real-life analogyNaN is a red stamp

Imagine a clerk stamping “not a valid answer” on a broken form. Any later calculation that uses that form is still tainted.

In real life: A form stamped invalid is not a usable answer
In JavaScript: NaN is not a usable number
In real life: Copies of the bad form stay bad
In JavaScript: Most calculations with NaN produce NaN
In real life: You need a special inspection
In JavaScript: Use Number.isNaN(value)

Where the analogy stops: NaN is still a JavaScript Number value, not an error object. Code keeps running unless you check for it.

Step through special values
Step 0 of 9Ready
Your turn: follow the blue line

Step through the strange-looking values. Each line was recorded from real JavaScript, including the coercing isNaN example.

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(NaN === NaN);console.log(Number.isNaN(NaN));console.log(isNaN("hello"));console.log(Number.isNaN("hello"));console.log(1 / 0);console.log(-1 / 0);console.log(Object.is(-0, 0));console.log(1 / -0);
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.
Special number values
ValueHow it appearsWhat to remember
NaN0 / 0, failed numeric parsingIt is not equal to itself. Prefer Number.isNaN over old coercing isNaN.
Infinity1 / 0, very large overflowIt is still a number value. It can move through later calculations.
-Infinity-1 / 0, 1 / -0The sign matters when direction matters.
-00 * -1, rounding a tiny negative value-0 === 0 is true, but Object.is(-0, 0) is false.

Think of Infinity as an odometer that has run out of digits: it is not a useful street address, but it tells you which direction the calculation went. Think of -0 like a thermometer showing -0° after rounding a tiny negative temperature.

Rounding & toFixed

STEP THROUGH

JavaScript gives you several rounding tools, and their differences are clearest with negative numbers. Math.round goes to the nearest integer, with halves moving toward +Infinity. Math.floor moves down, Math.ceil moves up, and Math.trunc simply drops the fractional part.

Compare rounding tools
Step 0 of 6Ready
Your turn: follow the blue line

Pick a value, predict each rounded result, then step through the functions one at a time.

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.round(value));console.log(Math.floor(value));console.log(Math.ceil(value));console.log(Math.trunc(value));console.log(value.toFixed(2));
CallStoreChangeResultRun = next line. Ran = already executed.
Recent returnsNothing yet. Start with the blue line.
Choose the value stored on line 1.

Changing the value starts a fresh replay, so predict the results again.

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 positive and negative halves
ExpressionResultWhy
Math.round(2.5)3Nearest integer; half moves toward +Infinity.
Math.round(-2.5)-2The same tie rule moves upward toward +Infinity.
Math.floor(-2.5)-3Floor means down the number line.
Math.trunc(-2.5)-2Truncation removes the decimal part, toward zero.
(1.005).toFixed(2)"1.00"The stored value is a hair below 1.005.
(2.345).toFixed(2)"2.35"This stored value rounds to 2.35 in current JavaScript engines.
Money tip

For prices, count in cents as integers: store 1299 instead of 12.99. Format for humans at the edge with (cents / 100).toFixed(2). The later Internationalization with Intl lesson shows proper currency formatting.

parseInt & parseFloat

INTERACTIVE

Form inputs and URL pieces often arrive as text. parseInt reads an integer from the start of a string. parseFloat reads a decimal number from the start. Number(...), which the Type conversion lesson covers in depth, tries to convert the whole value.

Parse text into numbers
Three conversion stylesPop out in the code editor (opens in a new tab)JavaScript
const input = "42px";console.log(parseInt(input, 10));console.log(parseFloat(input));console.log(Number(input));
Result table42px
parseInt(input, 10)42
parseFloat(input)42
Number(input)NaN
Try it yourself

parseInt and parseFloat scan from the start and stop when the text no longer fits. Number tries to convert the whole string, so it is stricter except for cases like the empty string.

No arbitrary code runs here: the playground passes your text to three built-in conversion functions.
Parsing examples
ExpressionResultReason
parseInt("42px", 10)42Reads digits, then stops at p.
parseInt("px42", 10)NaNThe string does not start with a number.
parseInt("3.99", 10)3Integers stop before the decimal point.
parseInt("101", 2)5Radix 2 means binary: 4 + 1.
parseInt("0x1F")31The 0x prefix means hexadecimal.
parseFloat("3.14abc")3.14Reads the decimal prefix and stops at a.
Number("42px")NaNThe whole string is not a number.
Number("")0One of conversion's surprising rules.
parseInt(0.0000005, 10)5The number becomes the string "5e-7", so parsing stops at e.
Always pass a radix

Use parseInt(text, 10) when you mean decimal. Radix makes your intent obvious, and it lets you parse other bases on purpose, like parseInt("101", 2).

The Math object

INTERACTIVE

Math is a built-in object full of number helpers. You do not create it; you call its functions directly. Common ones include Math.max, Math.min, Math.abs, Math.pow, Math.sqrt, Math.PI, and Math.random.

Useful Math helpers
ToolExampleResult
LargestMath.max(4, 9, 2)9
SmallestMath.min(4, 9, 2)2
No max argumentsMath.max()-Infinity
Absolute valueMath.abs(-8)8
PowerMath.pow(2, 5)32
Square rootMath.sqrt(49)7
Circle constantMath.PI.toFixed(3)"3.142"
Roll a real random die
Random integer from 1 to 6Pop out in the code editor (opens in a new tab)JavaScript
function rollDie() {  return Math.floor(Math.random() * 6) + 1;}console.log(rollDie());
Roll history0 rolls

No rolls yet.

Try it yourself

Click Roll once. Math.random() gives a decimal from 0 up to, but not including, 1.

Tests sample the rollDie helper many times to prove it stays in range.

The dice formula works because Math.random() is at least 0 and less than 1. Multiplying by 6 gives a decimal from 0 up to but not including 6. Math.floor turns that into 0 through 5, and + 1 shifts the range to 1 through 6.

Numeric separators

Long numbers are hard to read. Numeric separators let you put underscores between digits: 1_000_000 is the same value as 1000000. They are for humans only; JavaScript removes them while reading the literal.

Separators are only for readersPop out in the code editor (opens in a new tab)JavaScript
const population = 1_000_000;const cents = 12_50;console.log(population === 1000000);console.log(cents);
Separator rules
Allowed?ExampleWhy
Yes1_000_000Between digits.
Yes12_50Sometimes used for cents-like groups, though 1_250 is clearer for thousands.
No_1000Not at the start.
No1000_Not at the end.
No1__000Not doubled.
No1._5Not immediately after the decimal point.

Where you’ll use this

Number work appears whenever a page turns user input into a decision. A shopping cart parses quantities, keeps money in cents, rolls random recommendations, and rounds only when showing a value to a person.

Buggy money totalPop out in the code editor (opens in a new tab)JavaScript
const total = 0.1 + 0.2;console.log(total === 0.3);console.log(total.toFixed(2));
Safer cents totalPop out in the code editor (opens in a new tab)JavaScript
const cents = 10 + 20;console.log(cents === 30);console.log((cents / 100).toFixed(2));

The first example is fine for displaying with toFixed(2), but it fails exact equality. The second example keeps the total as the integer number of cents until the final display step.

Common misconceptions

“JavaScript has separate integer and decimal types.”

Every ordinary numeric value is a number. Integers are exact only inside the safe range.

“If a number prints as 0.3, it must equal 0.3.”

Printing often chooses a friendly short decimal. Equality checks compare the stored value.

“toFixed gives me a number.”

toFixed returns a string, because its job is display formatting.

“parseInt is just Number for whole numbers.”

parseInt scans a prefix. Number converts the whole string and has different empty-string rules.

“NaN means JavaScript threw an error.”

NaN is a value. It can spread through later arithmetic unless you check for it.

Practice: numbers in the wild

5 EXERCISES
Exercise 1 · Warm-upPredict float and special values

Predict all three printed lines before checking.

Starter codePop out in the code editor (opens in a new tab)JavaScript
console.log(0.1 + 0.2);
console.log(Number.isNaN(0 / 0));
console.log(Object.is(-0, 0));

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

    Exercise 2 · PracticeFix a money total

    The buggy code displays fine but fails equality. What unit should the program store internally?

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    const total = 0.1 + 0.2;
    console.log(total === 0.3);
    console.log(total.toFixed(2));

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

      Exercise 3 · PracticeWrite a dice roller

      Read the function. What is the smallest and largest possible return value?

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function rollDie() {
        return Math.floor(Math.random() * 6) + 1;
      }

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

        Exercise 4 · PracticeParse a weight

        Parse "12.5kg" so the decimal part is kept.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const input = "12.5kg";
        console.log(parseFloat(input));

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

          Exercise 5 · ChallengeRound to two decimals safely

          Use the helper to round 1.005 to cents. What does it print?

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function roundToCents(value) {
            return Math.round((value + Number.EPSILON) * 100) / 100;
          }
          console.log(roundToCents(1.005));

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

            Quiz: check your understanding

            7 QUESTIONS

            Pick an answer, then read every explanation. The wrong answers are designed to catch real beginner mistakes.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7What does the decimal sum code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(0.1 + 0.2);

              Choose an answer to see the explanation.

            2. Question 2 of 7What does the NaN check print?

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

              Choose an answer to see the explanation.

            3. Question 3 of 7What does this print?

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

              Choose an answer to see the explanation.

            4. Question 4 of 7Which expression returns the number 42 from "42px"?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              console.log(parseInt("42px", 10));

              Choose an answer to see the explanation.

            5. Question 5 of 7What can Math.max() return when called with no arguments?

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

              Choose an answer to see the explanation.

            6. Question 6 of 7Which numeric literal is valid?

              Choose an answer to see the explanation.

            7. Question 7 of 7What is typeof NaN?

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

              Choose an answer to see the explanation.

            Key takeaways

            • JavaScript’s everyday number type is a 64-bit IEEE 754 floating-point value.
            • Some decimals, including 0.1, are stored as tiny approximations.
            • NaN, Infinity, and -0 are real Number values with special rules.
            • toFixed returns display text; keep money as integer cents internally.
            • parseInt and parseFloat scan prefixes; Number converts the whole value.
            • Math gives you rounding, powers, square roots, constants, and random decimals.

            Remember the one-liner.
            JavaScript numbers are fast, useful approximations for decimals, exact for safe integers, and full of built-in helpers when you know the edge cases.

            Up next: Strings.

            CompleteFrontend Clear concepts. Working examples.