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:
console.log(0.1 + 0.2); // 0.30000000000000004
console.log(36.6 * 1.8 + 32); // 97.88000000000001
console.log(2 + 3); // 5Let's go through the output:
0.1 + 0.2gives not0.3but a number with an extra4in the seventeenth digit after the point.36.6 * 1.8 + 32also gets an extra1at the end.2 + 3gives exactly5.
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.1can 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:
console.log(1 / 0); // Infinity
console.log(-1 / 0); // -Infinity
console.log(0 / 0); // NaN
console.log(Math.sqrt(-1)); // NaNLet's see what happens here:
- dividing a nonzero number by zero does not stop the program: the result is infinity,
Infinityor-Infinity; - the calculations
0 / 0andMath.sqrt(-1)have no numeric answer, and JavaScript returnsNaN.
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:
const price = 3,5; // ✗
console.log(price);SyntaxError: Unexpected numberIn 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.2gives0.30000000000000004, and they are compared within a tolerance. - Dividing a nonzero number by zero gives
Infinityor-Infinity, while0 / 0andMath.sqrt(-1)giveNaN, 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.