Js and float

Synchronization published in my blog: jmingzi

When you learn a knowledge point of no direction, you can try to solve the problem at an angle to understand it.

For example this knowledge we can start with the following questions:

  • You see really is an integer of 1 to 1?
  • Why get is 0.1 + 0.2 .30000000000000004 instead .30000000000000004999?
  • Why security is the maximum number of 2 ^ 53--1?
  • How to avoid accuracy problems?
  • Constructors Number of static properties

Question one

We need to know js no real integer, we see values ​​are the result of v8 engine precision is omitted. In ecma-262 specification does not specify how the precision is omitted, so if another analytical engine, but may be another result.

1..toPrecision(4) === '1.000'

ToPrecision we can use to get the string representation of numerical precision, so js the number you have to have the feeling of "cross as many different angles," the.

Question two

By the problem that we know is the result of precision processing engine, then the problem is the same reason, the accuracy of 0.1 + 0.2 If the zoom view, of course, is to get

(0.1 + 0.2)..toPrecision(21) === '0.300000000000000044409' 

Guess: accuracy of the fractional part of the non-zero 17 default, if the end is 0 to continue omitted. Next, we start from the verification question three start from the principle.

Question three

javascript uses the IEEE 754 floating-point double-precision 64-bit representation, specified IEEE 754 floating-point representation of four, 64-bit double precision is one of them.

64-bit binary components:

 

  • 1 bit sign bit, represented by S, 0 represents a positive number of 1 stands for negative
  • 2 - 12 exponent bits, indicated by E, i.e., 2 ^ 11 = 2048, Qu value in the range of 0 to 2047, as is the double, so the exponent portion has a positive but also negative, taking a median of 1023 separated, meaning the value as E - 1023
  • 13 - 64-bit mantissa bits, represented by M

For example, the number 1 is represented by a binary "1" if we fill the 64-bit binary representation should be what is it?

  • Symbol S = 0
  • Index E - 1023 = 0, E = 1023
  • Mantissa M = 52

So we see the actual binary storage should look like this:

0 01111111111 0000...0000

After conversion tool to convert line below, you can verify the accuracy of the results:

 

 

http://www.binaryconvert.com/result_double.html

We then 0.1 + 0.2 authentication:

0.1.toString(2) 
// 0.00011001100...11010

0.1 64-bit binary converted into scientific notation: 1.10011001100...*10^-4that is

  • Symbol S = 0
  • Index E = 1023 - 4 = 1019
  • Mantissa M = 10011001100 ... 11010 next we can continue to verify the result of the conversion with online at:

 

 

We can find, in fact, ending in 1100 0.1 is constantly circulating, but we have seen the last four ending in 1010 which is due to hold only 52, the excess part will be discarded, discarded rules are defined by the IEEE 754 specification :

  • Rounding to the nearest: rounded to the nearest, as in the case of an even number closest priority (Ties To Even, which is the default rounding mode), the result will be rounded to the nearest value and may be expressed, but when There are two numbers as close to the time, that is even where the (Chinese ending in binary 0)
  • Rounding direction towards + ∞
  • Rounding towards -∞ direction
  • Rounding direction toward 0

In addition, the specification also agreed, due to the binary scientific notation is always 1. The beginning of a few, it will be omitted 1, so there are 53 to represent the mantissa. So binary mantissa part 0.1: 11001100 11001 ... so 53, the last one to enter into an even neighbor that is, to get 1010, so the resulting number is actually larger than the real 0.1.

Similarly, we see represented 0.2: 0.00110011001100...11010can be obtained mantissa part of it is the same, only the index one less.

 

Let us look at the three, maximum security Why is an integer 2 ^ 53--1? Why we can verify in turn 2 ^ 53 is no longer "safe" was.

 

We know that being a problem by the index up to 2047--1023 = 1024, why not 2 ^ 1024 it? We know the ending in the fact that there may be 53 represented (omitted 1), namely

// Math.pow (2, 53 is) .toString (2) 
2 ^ 53 is expressed in binary: 1000 ... a 1,53 000,1 a 0 // At this point mantissa most 53, No. 54 0 will be discarded 
2 ^ 53-1 represented in binary: 1111 ... 111,53 number 1 
2 ^ 53 + 1 is expressed in binary: 1000 ... 0001,1 a number 0, 1 1, 52

Wherein 2 ^ 53 + 1 due to the mantissa at most 53, must give it position 54 1, depending on the rounding rule, the even rounded, so give it a first 54, not into one. So get

2^53 === 2^53+1

 

That is 2 ^ 53 from the outset not represent a unique number, so just say 2 ^ 53-1 is the largest number of security.

Question four

Avoid the front of the scene is to show the accuracy of certain price, for example, the following formula:

Display price = commodity prices * * total number of + service charge ratio - price coupons

We commonly used methods are Number.toFixed (), Number.parseFloat (), Math.round (), what is the difference between them in order to know the figure out how to use them.

Number.toFixed (digits) Returns a string representation of the number of bits, it will be rounded off. E.g

1.005.toFixed(2) // 1.00

很显然不符合我们需求,为什么会这样呢?因为 1.005 这个数在 64 位二进制存储时是不能完全表示这个数的,我们放大精度看看

1.005.toPrecision(17)
// 1.0049999999999999

所以四舍五入的时候就将 499...99 舍掉了。

还记得问题三么?0.300000000000000044409 ,猜测的是是小数位 17 位,超过 17 位的部分会被四舍五入。因为做精度运算时都会做四舍五入:

1.005.toPrecision(16)
// 1.005000000000000

1.005.toPrecision(17)
// 1.0049999999999999

1.005.toPrecision(18)
// 1.00499999999999989

所以使用 toFixed 去做展示运算是不可靠的。

Number.parseFloat === parseFloat ,将字符串转换为浮点数表示,很显然转换后显示出来也会有精度问题,因为精确到哪一位呢?

我上面猜测说是:“小数部分的精度默认是非 0 的 17 位”,这是不准确的,例如:

1.005 * 100
// 100.49999999999999
100.49999999999999.toPrecision(20)
// 100.49999999999998579
'49999999999999'.length
// 14 并不是 17

所以 parseFloat 后的结果和我们直接写出来看到的数字是一样的,并不能够使用它直接参与计算。

Math.round() 返回一个数字四舍五入后最接近的整数,所以我们一般将浮点数放大为精度位的整数后再使用 Math.round() 得到四舍五入后的整数,再缩小精度位。

例如对于价格类,精度为 2,我们可以先乘 100 做运算后再除 100,此时得到的很可能是个精度位很长的数,我们只需要在展示时乘 100,Math.round 后再除 100 即可。

所以结论就是对于浮点数的计算,先放大,再做计算,计算完成后需要展示精度,可以使用 Math.round 四舍五入后,再缩小即可。

对于不需要做计算的浮点数直接展示,我们可以先 toPrecision 放大精度,再使用 toFixed() 到指定的精度。前提是放大的精度足够大,最好是 17 。

function round(num, precision) {
  const base = Math.pow(10, precision)
  return Math.round((num.toPrecision(17) * base).toFixed(1)) / base
}
round(1.005, 2)
// 1.01

Five questions

Number constructor has a static property as follows (negative direction has been ignored):

// maximum value can be expressed, infinitely close to 1024 ^ 2 
Number.MAX_VALUE
 // Maximum Security ^ 53 2 - 1 
Number.MAX_SAFE_INTEGER
 // positive infinity 1024 ^ 2 
Number.POSITIVE_INFINITY === Infinity
 // non-numeric 
Number. NaN equivalent to NaN

About Infinity and NaN Note that

  • Infinity === Infinity
  • The! == NaN
  • Infinity / infinity = NaN
  • 0 * infinity = NaN
  • Any number of operations and the results are NaN NaN
  • Any number / Infinity = 0
  • Infinity * Infinity = Infinity

I am concerned about the number of the public for more dry goods ~

Guess you like

Origin www.cnblogs.com/jhmydear/p/12067388.html