A function lets you understand’ Why 0.1+0.2! =0.3′

  Binary, Data type, Front end, javascript, number

Don’t say much, code first.

function judgeFloat(n, m) {
 const binaryN = n.toString(2);
 const binaryM = m.toString(2);
 Log (` $ {n} binary is ${binaryN} `);
 Log (` $ {m} binary is ${binaryM} `);
 const MN = m + n;
 const accuracyMN = (m * 100 + n * 100) / 100;
 const binaryMN = MN.toString(2);
 const accuracyBinaryMN = accuracyMN.toString(2);
 Log (` $ {n}+$ {m} binary is ${binaryMN} `);
 Log (` $ {accuracymn} binary is $ {accuracybinaryman} `);
 Log (` $ {n}+$ {m} binary to decimal is ${to10(binaryMN)} `);
 Log (` $ {AccurateMn} binary is converted to decimal again is $ {TO10 (AccurateBinaryMan)} `);
 Log (` $ {n}+$ {m} counts as $ {(to10 (binary Mn) = = = to10 (accurate binary ymn)) in js)?  '':' not'} exact');
 }
 function to10(n) {
 const pre = (n.split('.')[0] - 0).toString(2);
 const arr = n.split('.')[1].split('');
 let i = 0;
 let result = 0;
 while (i < arr.length) {
 result += arr[i] * Math.pow(2, -(i + 1));
 i++;
 }
 return result;
 }
 judgeFloat(0.1, 0.2);
 judgeFloat(0.6, 0.7);

Due toJavaScriptThere is no decimal inBinaryConvert toDecimal systemMethod, so manually implemented a.

image

First, let’s come to a simple conclusion.

All the data in the computer is based onBinaryStored, so the computer must first convert the data intoBinaryTo calculate, and then in the calculation results intoDecimal system.

It is not difficult to see from the above code, in the calculation0.1+0.2At that time,BinaryThe calculation lost precision, resulting in reconversion intoDecimal systemThe results were not in line with the expected results.

In fact, there are some theme parties. A function does not allow you to understand it in depth. You have to continue to look at the following …

Analysis of Results-More Questions

0.1And0.2The binary numbers of the are all decimals with 1100 infinite cycles. Let’s look at the results calculated by JS one by one.

Binary of 0.1

0.0001100110011001100110011001100110011001100110011001101

Binary of 0.2

0.001100110011001100110011001100110011001100110011001101

In theory, the sum of the above results should be:

0.0100110011001100110011001100110011001100110011001100111

The binary of 0.1+0.2 calculated by actual JS

0.0100110011001100110011001100110011001100110011001101

As a code obsessive-compulsive disorder, I have a new problem:

Is there so many bits instead of more in the 0.1 binary calculated by Why js? ? ?

Is the binary result of (0.1+0.2) calculated by Why js different from that of (0.1+0.2) calculated by ourselves? ? ?

Why 0.1 binary+0.2 binary! = 0.3 binary? ? ?

How js Stores Binary Decimal Numbers

decimalBinaryMost of them are infinite loops,JavaScriptHow do you store them?

InECMAScript® language specificationAs can be seen in,ECMAScripthit the targetNumberType complianceIEEE 754Standards. It is represented by a 64-bit fixed length.

In fact, many languages follow this standard for numeric types, for exampleJAVASo many languages have the same problems as above.

So don’t spray when you meet this kind of problem next time.JavaScript

If you are interested, you can look at this website.http://0.30000000000000004.com/Yes, you are right, that ishttp://0.30000000000000004.com/! ! !

IEEE 754

The IEEE754 standard contains a binary representation of a set of real numbers. It consists of three parts:

  • Sign bit
  • Exponential bit
  • Ending digit

The number of bits in each part of floating point numbers with three precision is as follows:

image

JavaScriptIt uses 64-bit double-precision floating-point encoding, so itsSign bithold1Bits, Index Bits11Bits, mantissa bits accounted for52Bits.

What do we understand belowSign bitExponential bitEnding digitIn order to0.1For example:

Its binary is:0.0001100110011001100 ...

In order to save storage space, it is expressed by scientific counting in computers, that is

1.100110011001100 ...X 2-4

If this is not easy to understand, think about decimal numbers:

1100The scientific counting method of is11X 102

So:

image

Sign bitIs to identify the positive and negative,1showNegative,0showPositive;

Exponential bitStore the index of scientific counting method;

Ending digitStoring the effective number after scientific counting method;

Therefore, the binary we usually see is actually the mantissa bits actually stored by the computer.

ToString(2 in js (2)

Since mantissa bits can only be stored52A number, this can explaintoString(2)The results of the implementation of the:

If the computer does not have storage space limitations, then0.1TheBinaryShould be:

0.00011001100110011001100110011001100110011001100110011001  ...

Scientific counting mantissa

1.1001100110011001100110011001100110011001100110011001  ...

However, due to restrictions, the number of significant digits is53Bits and subsequent numbers cannot be stored, it follows, if so1Just move forward1If it is0The principle of abandoning.

The 53rd bit of the binary scientific counting method of 0.1 is 1, so the following results are obtained:

0.0001100110011001100110011001100110011001100110011001101

0.2With the same problem, in fact, it is precisely because of such storage that there is a loss of precision, which leads to0.1+0.2! =0.3.

As a matter of fact, there are still many calculations with the same accuracy problem. We cannot write them all down, so when there are numerical calculations in the program, we’d better use the tool library to help us solve them. Here are two recommended open source libraries:

Now let’s look at the other two questions above.

Why is the binary of 0.1 calculated Why JavaScript so many bits instead of more? ? ?

AbovetoStringThe principle helps us to solve this problem, in the effective number first53Figures after bits will follow1 into 0The principle of, only allowed to store in memory52A significant number.

Why is the binary result of (0.1+0.2) calculated Why JavaScript different from that of (0.1+0.2) calculated by ourselves? ? ?

Our own calculation of 0.1+0.2:

0.0100110011001100110011001100110011001100110011001100111

In fact, the effective number of this result has exceeded52Bit, we will proceed from the end1 into 0The following results were obtained

0.0100110011001100110011001100110011001100110011001101

The maximum number that JavaScript can represent

By andIEEE 754Limitations of double precision 64-bit specification:

Exponential bitThe maximum number that can be expressed:1023(Decimal)

Ending digitThe maximum number that can be expressed is the mantissa bit1The situation of

So the largest number JavaScript can represent is acceded to the throne

1.111 ...X 21023This result is converted to decimal1.7976931348623157e+308The result isNumber.MAX_VALUE.

Maximum safety figure

In JavaScriptNumber.MAX_SAFE_INTEGERIndicates the maximum safety figure. The calculation result is9007199254740991That is, there will be no loss of precision (except decimals) within this range of numbers, which are actually1.111 ...X 252.

We can also use some open source libraries to handle large integers:

In fact, the government has also considered this issue.bigIntType ines10It has been proposed in, nowChromeIt is already available in.

BigInt type

BigIntIt is the seventh primitive type.

BigIntIs an integer with any precision. This means that variables can now be calculated9007199254740991That is, the number above the maximum safe integer.

const b = 1n;  //append n to create BigInt

In the past, greater than was not supported.9007199254740992The integer value of. If it exceeds, the value will be locked toMAX_SAFE_INTEGER + 1:

const limit = Number.MAX_SAFE_INTEGER;
⇨ 9007199254740991
limit + 1;
⇨ 9007199254740992
limit + 2;
⇨ 9007199254740992 <--- MAX_SAFE_INTEGER + 1 exceeded
const larger = 9007199254740991n;
⇨ 9007199254740991n
const integer = BigInt(9007199254740991);  // initialize with number
⇨ 9007199254740991n
const same = BigInt("9007199254740991");  // initialize with "string"
⇨ 9007199254740991n

typeof

typeof 10;
 ⇨ 'number'
 typeof 10n;
 ⇨ 'bigint'