In JS, only the number type is used. There is no distinction between integer and floating point

In js, the number is encoded as a 64-bit double precision floating point number in IEEEF 754, so 1 === 1.0 is true, which means there are no decimals at all. All numbers are 64 bit double. (It is confusing that the bit operation can only be done with integers, so js automatically converts 64 bit double to 32 bit integer.)

IEEE 754

The IEEE Binary Floating-point Arithmetic Standard is the most widely used standard for floating-point arithmetic operations since 1980. It is adopted by many cpus and floating-point operators. It defines the format of floating-point numbers (including negative zero-0), abnormal values, and special values (infinite, non-numerical), and the floating-point operators for these values.

IEEE 754 specifies four ways to identify floating point values: single (32-bit), double (64-bit), extended (43 bits and more, rarely used), and extended double (79 bits and more, usually implemented as 80 bits).

Floating point profiling

value = sign * exponent * fraction

That is, the actual value of the float is equal to the sign bit times the exponential offset times the fraction value

Here’s an explanation:

We all know scientific numeration, which involves taking a number such as: 123465.555 can be written as 1.2346555*105, which is similar to the decimal notation. For example, 16.25(decimal) => 10000.01 can be written as 1.000001 * 24, so the fraction value is 000001(the integer is omitted, which will be discussed later). The exponent is 4(this is not the exponential offset)

Present the

Binary floating-point numbers are stored in signed numerical notation (0 for a positive number and 1 for a negative number), where the highest bit is designated as the sign bit, the “exponent part” is the next most significant e bits to store the exponent, and the last remaining f less significant bits, Stores the fractional part of the “significant number” (i.e., the value of the fraction in the scientific notation above, which defaults to 0 in the non-canonical form and to 1 otherwise)

Exponential offset

The exponent offset value, that is, the encoded value of the exponent domain in the floating-point representation, is equal to the actual value of the exponent plus a fixed value specified by the IEEE 754 standard to be 2E-1-1, where e is the bit length of the stored exponent

For example, a single-precision floating-point number has an exponent field of 8 bits, Then it has a fixed offset of 28-1-1 = 128-1 = 127, which is “the representation of a signed number”. The exponent part of a single-precision floating-point number actually has a value from -126 to 127(-127 and 128 are used for special value processing, see below for non-canonical floating-point numbers and special values). For example, the actual value of the exponent is 17, and the encoded value of the exponent in single-precision floating-point numbers is 144, which is 144 = 17 + 127.

The exponent of floating point number is expressed by the actual value of the exponent plus the fixed offset value. The advantage is that the value of all exponentials can be expressed by an unsigned integer of length e bits, which makes it easier to compare the exponent size of two floating point numbers. The exponent part represented by the shift code here is also called the order code

A floating point number in canonical form

If the encoding value of the exponent part of a floating-point number is between 0 < exponent < 2****e **-2, and the most significant bit (that is, the integer number) of the fraction is 1 in the scientific representation, ** the floating-point number is called a canonical floating-point number,

Since the mantissa under this representation has an implied binary significant digit, in order to distinguish it from the mantissa of binary scientific notation, IEEE 754 calls it a significant number. The integer part is 0 or 1 if it’s not specified otherwise it’s omitted so there’s an implied binary significant digit)

For example, the size of a single-precision (32-bit) floating point in the specification is 00000001-111110 in the exponent offset and 0000…. in the fractional part 000-1111… (23 1111 bits).

A floating point number in a non-canonical form

If * * index part of floating point Numbers code is 0, non-zero score part, * * the floating-point floating point Numbers, known as the code is usually a pretty close to zero, will use the form of the convention, the IEEE 754 rules, said: the statute index of floating point Numbers in the form of offset value than the statute index of floating point Numbers in the form of small offset value 1,

For example, the exponent domain encoding value of the minimum specification form of single-precision floating point number is 1, and the actual value of the exponent domain encoding value is -126, while the exponent domain encoding value of the non-specification single-precision floating point number is 0, and the actual value of the corresponding exponent is -126 instead of -127.

In fact, the non-canonical floating-point numbers are still valid and can be used, but their absolute values are less than all the canonical floating-point numbers, that is, all the non-canonical floating-point numbers are closer to 0 than the canonical floating-point numbers, and the mantissa of the canonical floating-point numbers is greater than 1 and less than 2, while the mantissa of the canonical floating-point numbers is less than 1 and greater than 0.

Special values

1. If the exponent is 0 and the decimal part of the mantissa is 0, then the number is plus or minus 0(plus or minus depends on the sign bit).

2. If the exponent = 2e – 1 and the mantissa part is 0, the number is ±∞ (positive or negative depending on the sign bit).

3. If the exponent = 2e-1 and the fractional part of the mantissa is non-zero, the number is represented as a non-number (NaN).

64-bit double

Double precision binary decimal stored in 64 bits

S is the sign bit, Exp is an exponential word, Fraction is a significant number, and the exponential part is represented by the so-called partial value, which is the sum of the actual exponent and a fixed value (1023 in the case of 64 bits).

Said in this way the purpose is to simplify the comparison, because the index values may also have negative may also is positive, if use complement way, all the sign bit S and Exp own the sign bit will lead to can’t simple comparison of the size, because of this, index part usually adopt an unsigned integer value is stored, The exponent part of the double is -1022 to +1023 plus 1023, and the exponent value is 1 to 2046(0, 2, all zeros and 2047, 2, all 1s are special values). When calculating a floating-point decimal, the exponent value minus the offset value will be the actual exponent size.

Comparison of floating point numbers

Floating-point numbers can basically be compared lexicically in the order of sign bits, exponent fields, and mantisse fields. Obviously, all positive numbers are greater than negative numbers. If the sign is the same, the larger binary representation of the exponent has a larger floating point value

Rounding of floating point numbers

For example, the mantissa of the 64-bit double precision floating point number is 52 bits, and the mantissa of the 32-bit single precision floating point number is 23 bits. The precision of the representation of the floating point number format is limited. When converted to the floating point number format, the redundant bits must be discarded.

Rounding to the nearest (default) : Rounding to the nearest, even takes precedence in the case of the same approximation: Rounding to the nearest representable value, but when two numbers are the same, the even number (ending in a zero in binary) is selected. This is also called rounding to the even number

2. Round to infinity: Round the result to infinity, also called round up

3. Round to negative infinity: Round the result to negative infinity, also called rounding down

4. Rounding to 0: Rounding the result to 0, also called rounding to 0

The following are examples of the four rounding methods:

Here’s an explanation of rounding to nearest:

Now, you might be wondering: Why do I use rounding instead of rounding, as we’re used to?

Its reason can understand it, in the rounding, the last digits from 1 to 9, give a 1, 2, 3, 4, it can exactly and carry 9, 8, 7, 6, and 5 had been left alone to carry, if using round each time will be 5 carry, at the time of a large number of data statistics, In the case of rounding to even numbers, the probability of 5 rounding or carrying is about the same in most cases, and the deviation is correspondingly smaller when a large number of calculations are performed

In the decimal case:

For example,

1.234999 rounding to 1.23,

1.2350001 rounds to 1.24

For 1.23499, compared with 1.24, 1.23 is the closest to the original number 1.234999

Compared with 1.2350001, 1.23 and 1.24, 1.24 is the closest to the original number 1.2350001

1.2350000 rounds to 1.24

Here for the original number 1.235000, 1.23 and.124 are the same distance from the original number, but 4 is even so we round to 1.24

In the binary case:

For example,

1.001 011 Rounds to 1.001

1.001 1.001 011 | | = 0.000 011

1.010 1.001 011 | | = 0.000 100

You can clearly see that the front value is closer to the original value, so the rounded result is 1.001

1.001 101 rounds to 1.010

1.010 1.001 101 | | = 0.000 010

1.001 1.001 101 | | = 0.000 101

You can clearly see that the front value is closer to the original value, so the rounded result is 1.010

From this we can conclude two rules:

If the significant bit is 0, and the value to be rounded is less than half, you should round down,

If the value to be rounded is greater than half of the value to be rounded if the significant digit is followed by a 1 and the following digits are not all zeros, then the value should be rounded up

In both cases, we look at special cases, the effective bit is 1, following behind all digits are zero, the value will be eliminated just half, at this time at this point we need to choose to even number rounding, rounding the numerical upward or downward, make the least significant bit of the result even, in the case of binary is zero, So 50% of the time it’s rounding up, 50% of the time it’s rounding down,

1.001 100 rounds to 1.010

In this case, the distance between 1.010 and 1.001 is equal to 1.001 100. According to the rounding principle of even numbers, 1.010 is taken

From this example we can see that if the value to be rounded is exactly half, the least significant bit is rounded up if it is odd, and down if it is even, so that the least significant bit is always even

0.1 + 0.2

0.1+0.2=0.30000000000000004 has been a classic problem, and there is even a website dedicated to the calculation of 0.1+0.2 in each language 0.30000000000000004.com/

Here we calculate it manually with the aforementioned IEEE 754 standard

First convert 0.1 and 0.2 to binary. Convert from decimal to binary using “round by 2, order”.

0.1 to binary calculation is as follows:

0.1 * 2 = 0.2 The integer part is 0

0.2 * 2 = 0.4 The integer part is 0

0.4 * 2 = 0.8 The integer part is 0

0.8 x 2 = 1.6 The integer is 1

0.6 x 2 = 1.2 The integer part is 1

0.2 * 2 = 0.4 The integer part is 0

0.4 * 2 = 0.8 The integer part is 0

0.8 x 2 = 1.6 The integer is 1

0.6 x 2 = 1.2 The integer part is 1

0.2 * 2 = 0.4 The integer part is 0

0.4 * 2 = 0.8 The integer part is 0

0.8 x 2 = 1.6 The integer is 1

0.6 x 2 = 1.2 The integer part is 1

.

0.1 in decimal is 0.0 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011… The cycle of 0011

Since it is an infinite repeating decimal, rounding must occur when converting to a floating point number for storage,

1. We convert this infinite repeating decimal into scientific notation 1.1 0011 0011 0011 0011… * 2-4

2. The mantissa part is stored as a fraction (the default value for integer is 0, and all other cases are 1), so the fraction part is stored as 1 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011…

3. If the mantissual part is 52 bits, the 53rd bit is 001 —- 1. At this time, according to the principle of rounding up when the first bit after the significant bit is 1 and the last bit is not completely 0,

Binary 0.1 after final rounding is 0.0 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010

0.2 similarly, 0. 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 0011 010

So the binary 0.1 plus 0.2 is

0.00011001100110011001100110011001100110011001100110011010

+ 0.00110011001100110011001100110011001100110011001100110100

Note: the binary of 0.2 is one bit less than the binary of 0.1, so you need to add a zero

The results of 0.01001100110011001100110011001100110011001100110011001110

The value is converted to 0.30000000000000004 in decimal

Therefore, the problem of 0.1 + 0.2 is that the binary numbers of 0.1 and 0.2 are infinite repeating decimals, while the data stored in JS is a 64-bit double precision floating point number, which occurs rounding, resulting in the result of 0.30000000000000004

Safe integer and value range

Security integer

According to the IEEE 754 standard, it is not difficult to conclude that the number beyond the mansiness range will be rounded, resulting in accuracy problems, so the safe value range in JS is -253 to 253 without two endpoints

(2 does math.h pow). ToString (2) / / "100000000000000000000000000000000000000000000000000000" math.h pow. (2) does the toString (2) length / / "54" (math.h pow does (2) - 1). The toString (2) / / "11111111111111111111111111111111111111111111111111111" (Math. Pow does (2) - 1). The toString (2). The length / / 53Copy the code

Why is it 53? Because the integer bits are omitted after the conversion so it’s exactly 52 bits, right

The code to verify a secure integer is as follows

Math.pow(2, 53) // 9007199254740992 9007199254740992 // 9007199254740992 9007199254740993 // 9007199254740992 Math.pow(2, Math.pow(2,53) + 1 // true math.pow (2,53)-1 // 9007199254740991 Math.pow(2,53)-2 9007199254740990Copy the code

Numerical range

Mantissa part control accuracy, exponential part + mantissa part control range

Maximum value: the exponential domain of a 64-bit double precision floating point number is 11 bits, so the maximum value of the exponential bit is 211-1 = 2047. Because the exponential domain is an unsigned representation, and the fixed number 1023 is added, the maximum value of the exponential part is 2047-1023 = 1024

That is, if a number is greater than or equal to 2 to the 1024 it will have a forward overflow.

The test code is as follows

Math.pow(2,1024) // Infinity math.pow (2,1023) // 8.98846567431158e+307Copy the code

Now, you might wonder, why do we do this

Just to explain, the exponential part is at maximum 1024, which is the scientific notation, where the decimal point is offset, which is x.xx * 21024,

You can look at this example

Math.h pow (2102 3). The toString (2) / / 1000000000... Math.h pow (2102 3). The toString (2). The length / / 1024Copy the code

2 to the power of 1023 is converted to a binary length of 1024, so it is converted to a scientific notation of 1 * 21023

Minimum is worth words is very simple, if a number less than or equal to 2-1075 (minimum – 1023 index part, plus the decimal part 52), then the negative overflow occurs, there are some wrong, can be called close to the minimum value of 0) js can’t said At this time will directly returns 0 (note that this is not a negative, The smallest number close to 0 is the exponential part of the negative pull full, the decimal part is 0000000….. 1)

  Math.pow(2, -1075)
Copy the code

So js can represent values ranging from 21024 to 2-1075 without two endpoints

Reference links:

Zh.wikipedia.org/wiki/IEEE_7…

Javascript.ruanyifeng.com/grammar/num…

My.oschina.net/u/4081479/b…

Cloud.tencent.com/developer/a…

Fengmumu1. Making. IO / 2018/06/30 /…

Liguixing.com/archives/12…

Juejin. Cn/post / 684490…

Juejin. Cn/post / 684490…

Zhidao.baidu.com/question/28…