There is a very common interview question

0.1 + 0.2 === 0.3 // true ? false
Copy the code

You probably know it’s false, but why isn’t it equal? I will explain it in terms of floating-point representation and floating-point precision

Javascript floating point representation

There is no distinction between integer and floating point in Javascript. There is only one type Number, which follows the IEEE Binary Floating point Arithmetic standard (IEEE754) and is stored using 64-bit double.

Double precision memory is known, how does that precision floating point number store data? There are several key points

1. Double – precision floating – point numbers use 64-bit storage

  • Sign (S) : indicates the sign bit. The length is 1, 0 indicates that the number is positive, and 1 indicates that the number is negative
  • 1. Exponent (E) : an exponential bit of length 11, used in binary scientific notation
  • Mantissa (M) : mantissa bits, length 52, mantissa bits of binary scientific computation

The calculation formula of the value is (binary) :


2. UseBinary scientific notation

Here’s an example:

Convert to binary representation

Convert to binary scientific notation

3. The exponent bit represents a signed integer

Because the exponential bit value is an unsigned integer with a range of [0, 2047], the normalized value is [1, 2046]. However, the exponential bit needs to represent a signed integer, so [1, 1022] is negative [-1022, -1], 1023 is 0, [1024, 2046] is positive [1, 1023], so the range of the whole exponential bit is [-1022, 1023].

The formula can be derived from the above:


  • E: indicates the number represented by the exponential bit
  • E: indicates the actual value stored

Here’s an example:

In binary scientific notation, E = -1, E = 1022

Tips: What are normalized values and other values

4. Mantissa does not represent the integer part of a binary scientific calculation, i.e., 1

Because the normalized number of integer bits are 1, so in storage can save space, does not represent the integer bits, starting from small digits. So the mantissa actually represents up to 53 digits

The formula can be derived from the above:


  • M: A numeric value represented by bits
  • F: The number of digits actually stored

Here’s an example:

Binary scientific notation, M=1, then the actual storage f=0,

From above, the numerical calculation formula can be deduced as


Nonnormalized values and special values

So the question is, if I follow the formulaSo how do I represent 0? Even if you set f = 0 and e= any value, the formula says value can’t be 0. Of course, the first formulaNo problem, the problem is the derivation of the formula, because the derivation of the formula only conforms to the normalized values, and I will introduce normalized values and other values

  • Normalized values: e is not all 0 and not all 1, and f is any value

  • Nonnormalized values: e are all 0 and f is any value. Nonnormalized values are used to represent 0 and numbers close to 0. At this point, the formula is



  • Infinity: e is all 1, f is 0

  • NaN: e is all 1, f is not 0

So: when e = 0, f = 0, represents the value 0

Explain 0.1 + 0.2! = = 0.3

So now we can explain why 0.1 + 0.2 is not equal to 0.3

Represented as binary:

Convert to binary scientific notation:

S = 0, E = -4, M = 1.1001100… 1100… 1100… , then S = 0, e = 1029, f = 1001100… 1100… 11010

Re-represent the truncated (rounded) value as binary, then the final binary value of 0.1 is:0.00011... 0011... 001101

Similarly, binary values of 0.2 and 0.3 are represented

0.1:0.0001100110011001100110011001100110011001100110011001101 0.2: 0.001100110011001100110011001100110011001100110011001101 0.3: 0.1 + 0.2 and 0.010011001100110011001100110011001100110011001100110011 as follows: / / the following will introduce the steps for details and compared with 0.3 to 0.0100110011001100110011001100110011001100110011001101, found that is not equal, middle difference is: 0.000000000000000000000000000000000000000000000000000001Copy the code

From the point of view of the result value, the intermediate difference is already very, very small, can be ignored. In fact, in the ES6 Number extension, addNumber.EPSILONProperty representing the difference between 1 and the minimum floating point value greater than 1, with a value ofWhen the value is smaller than number. EPSILON, it can be ignored

Floating point accuracy

rounding

The mantissa bit can only store 52 bits, but the real numbers between 0 and 1 are infinite. How to express these infinite numbers? Since full representation is impossible, you have to discard some values to find the closest floating-point match. So what kind of rounding method do you use? Common rounding methods are described below

  • Rounding to even: Also called rounding to the nearest value
  • Round to zero: Discard values other than the last bitMath.truncunderstand
  • Rounding to positive infinity: Rounding to larger numbers can be done as followsMath.ceilunderstand
  • Rounding to negative infinity: Rounding to smaller numbers can be done byMath.floorunderstand

IEEE754 uses rounding to even numbers. The principle is to ensure minimum loss accuracy. The following is a brief introduction to rounding rules

  1. forRight in the middleIf the last digit of the reserved digit is even, the subsequent value is discarded, and the odd digit is carried. For example,1/2 to retain.1/2 to retain
  2. For values closer up, carry. Such as1/2 to retain
  3. For a downward value that is closer, it is discarded. Such as1/2 to retain

Here’s an example:

0.1 = > 0.0001100110011001100110011001100110011001100110011001100 | 110011... // Since the last digit needs to be reserved 110011... , fashionable are near the value of the upward, should carry, so 0.1 = > 0.0001100110011001100110011001100110011001100110011001101Copy the code
  • “|” said there need to rounding

Tips: If you really can’t figure out how to round, there’s an easy way. Round down, subtract from the original number; Then round up, subtract from the original number, compare the two differences and take the number with the smaller absolute value of the difference; If the differences are equal, the number ending in an even number is taken

To calculate

In order to further ensure accuracy, IEEE754 standard, when double precision is calculated in the middle, extra three digits are reserved, namely, the protection bit, the rounding bit and the paste bit

  • Protection bit: one bit to the right of the lowest precision (double precision can be understood as the 53th mantissa)
  • Rounded bit: one bit to the right of the protection bit
  • Paste bit: One bit to the right of the round bit, indicating whether there is any data to the right of the round bit. If there is any data to the right of the round bit, the paste bit is 1; otherwise, it is 0. The purpose is to support the rounding of the target value to the nearest even number

When a floating-point number is calculated, it increases the accuracy of the calculation by saving an extra three digits to find the closest match of the floating-point number.

Simulate 0.1 + 0.2 calculation

With all that said, I’d like to briefly write the binary calculation of 0.1 + 0.2.

0.1: S = 0, E = 4, 0.2 M = 1.1001100110011001100110011001100110011001100110011010: S = 0, E = 3, M = 1.1001100110011001100110011001100110011001100110011010 / / to order small order for big order 0.1: S = 0, E = 3, M = 0.2 0.11001100110011001100110011001100110011001100110011010: S = 0, E = 3, M = 1.1001100110011001100110011001100110011001100110011010 / / M value addition and as follows: Calculate the 0.3 10.01100110011001100110011001100110011001100110011001110: S = 0, E = 3, 10.01100110011001100110011001100110011001100110011001110 M = 0.3 / / normalized calculated: S = 0, E = 2, M = 1.0011001100110011001100110011001100110011001100110011 | 10 / / calculation, the right for two, here to protect a = 1, rounding a = 0, Paste a = 0 / / rounding after calculated 0.3: S = 0, E = 2, M = 1.0011001100110011001100110011001100110011001100110100 0.3 of floating-point Numbers: S = 0, E = 2, M = 1.0011001100110011001100110011001100110011001100110011 / / convert decimal to calculate 0.3 = 0.30000000000000004Copy the code
  • “|” said should be truncated, the subsequent numerical is the protection, rounding, paste

reference

  • Understanding computer systems in depth. Chapter 2
  • “Computer composition and design of software/hardware interfaces.” chapter 3
  • Wikipedia IEEE 754