Skip to content
Theory · Variables and types · lesson 5 of 9

Numbers

Picture a calculator whose screen fits only nine digits after the decimal point. Divide 1 by 3 on it: it shows 0.333333333 and drops the remaining threes. Add three such thirds on paper, and you get 0.999999999, not one. No digit was computed wrong: the screen ran out of room.

A computer also stores a number in a limited space. That is why adding two fractional numbers in JavaScript can give a different result from the one on paper:

JavaScript
console.log(0.1 + 0.2);  // 0.30000000000000004
console.log(36.6 * 1.8 + 32);  // 97.88000000000001
console.log(2 + 3);  // 5

Let's go through the output:

  1. 0.1 + 0.2 gives not 0.3 but a number with an extra 4 in the seventeenth digit after the point.
  2. 36.6 * 1.8 + 32 also gets an extra 1 at the end.
  3. 2 + 3 gives exactly 5.

This does not happen with whole numbers, but with fractions an extra digit at the end shows up regularly. The reason is how the number type works.

One type for all numbers

Whole and fractional numbers in JavaScript are values of one type, number. Inside, each such number is stored in binary, with a limited number of digits set aside for it. Binary is writing a number with the digits 0 and 1 only: that is how a computer stores any data.

Whole numbers are stored exactly as long as their size does not exceed 9,007,199,254,740,991, so 2 + 3 gives exactly 5.

Rounding error

The fraction 0.1 is endless in binary, like 1/3 in decimal, and has to be cut off. The result is a rounding error: the number is very close to 0.1, but not equal to it. Errors add up in a sum and become visible in the output, as in the first line of the program.

Here the calculator analogy stops working. The calculator counts in decimal, and 0.1 fits on its screen exactly. A computer counts in binary, so it cuts off even 0.1.

Because of the error, fractional results are compared not for exact equality but within a tolerance. Two numbers count as equal if they differ by less than, say, 0.000000001. The difference is taken without its sign: Math.abs(x) returns the number x without a minus, and Math.abs(2 - 5) gives 3. The course exercises check answers this way too.

Sums of money are often stored in cents, that is, as whole numbers. Then no rounding error comes up at all.

Interviewers like to ask this: "Why is 0.1 + 0.2 not equal to 0.3?" The answer has two parts:

  • a number is stored in binary with a limited number of digits, and 0.1 can be written there only approximately;
  • that is why fractional results are compared within a tolerance, and money is counted in whole cents.

Infinity and NaN

Not every calculation gives an ordinary number. For such cases the number type has special values. The / operator divides one number by another, and Math.sqrt(x) computes a square root:

JavaScript
console.log(1 / 0);  // Infinity
console.log(-1 / 0);  // -Infinity
console.log(0 / 0);  // NaN
console.log(Math.sqrt(-1));  // NaN

Let's see what happens here:

  • dividing a nonzero number by zero does not stop the program: the result is infinity, Infinity or -Infinity;
  • the calculations 0 / 0 and Math.sqrt(-1) have no numeric answer, and JavaScript returns NaN.

You have already met NaN: it is the "not a number" value, which also belongs to the number type. None of these calculations causes an error: the program goes on working with the resulting Infinity or NaN. If you add, multiply or divide NaN and a number, the result is NaN too.

Common mistake

The fractional part was separated with a comma, as Russian and many other languages do:

JavaScript
const price = 3,5;  // ✗
console.log(price);
TEXT
SyntaxError: Unexpected number

In JavaScript a comma separates values, and a dot separates the fractional part. The program does not start at all: a SyntaxError is found before the first line. The fixed line is const price = 3.5;.

Key points

  • Whole and fractional numbers are one type, number; whole numbers up to 9,007,199,254,740,991 are stored exactly.
  • Fractional numbers are stored approximately, so 0.1 + 0.2 gives 0.30000000000000004, and they are compared within a tolerance.
  • Dividing a nonzero number by zero gives Infinity or -Infinity, while 0 / 0 and Math.sqrt(-1) give NaN, and the program does not stop.
  • In code, the fractional part is separated with a dot, not a comma.

Subscribe to take the course

The course is free. Sign in with Telegram and subscribe to the channel to open every lesson.

Sign in another way