0.1+0.2 === 0.3吗?

目的:了解题目描述的问题

  1. 答案: 不等于。
  2. IEEE 754 只能表示1/2,1/4, 不能表示1/10

0.1和0.2在计算机中的二进制存储会让它们本身损失掉一定的精度,而它们在计算机中的二进制存储转换成十进制时已经不是真正的0.1和0.2了,相加的结果也就自然不是0.3了

0.1如何转化为二进制

0.1*2 = 0.2 取整数0
0.2*2 = 0.4 取整数0
0.4*2 = 0.8 取整数0
0.8*2 = 1.6 取整数1
0.6*2 = 1.2 取整数1
.等等等

5.5 如何转化为二进制

5.5 转二进制 =====> 101.1 科学计数法 =====> 1.011*2^2
存入计算机:
符号位:0
指数位:2 加1023 =====> 1025 转二进制 =====> 10000000001
尾数位:1.011 隐去小数点左边的1 =====> 011

如何解决浮点误差

1. 判断类

不可能有限空间处理无限小数,所以对于判断类的,用toPrecision+parseFloat

// 一般精度12就够了
function strip(num, precision = 12) {
  return +parseFloat(num.toPrecision(precision));
}

2.运算类

  1. 取精度(使用toFixed解决(注意: 1.005.toFixed(2) === 1.00,而不是1.01)
  2. 字符串相加。
  3. 三方库使用bignumber。js解决,但是性能稍微差点。

为什么let a = 0.1, a 就等于0.1

如果一个 IEEE 754 的双精度浮点数被转成至少含17位有效数字的十进制数字字符串,当这个字符串转回双精度浮点数时,必须要跟原来的数相同;换句话说,如果一个双精度的浮点数转为十进制的数字时,只要它转回来的双精度浮点数不变,精度取最短的那个就行

拿0.1来举例子,0.1和0.10000000000000001转成双精度浮点数的存储是一样的,所以取最短的0.1就行了。

Number.prototype.toPrecision()
toPrecision() 方法以指定的精度返回该数值对象的字符串表示。

Number(100).toString(2) —> ‘1100100’ 十进制转
var num = 1100100;
console.log(parseInt(num,2));

iEEE 754 浮点数如何存储

  1. 双精度存储,1个符号位+11个指数位+52个尾数位
  2. 最大值和最小值。
  3. 安全最大值和安全最小值。
  4. 转换公式

注意

为什么1.005.toFixed(2)=1.00而不是1.01

1.005.toPrecision(6) = == 1.00499

//通过isEqual工具方法判断数值是否相等
function isEqual(number1, number2, digits){
    
    
  digits = digits == undefined? 10: digits; // 默认精度为10
  return number1.toFixed(digits) === number2.toFixed(digits);
}
console.log(isEqual(1.0-0.7, 0.3));  //true
//原型扩展方式,更喜欢面向对象的风格
Number.prototype.isEqual = function(number, digits){
    
    
  digits = digits == undefined? 10: digits; // 默认精度为10
  return this.toFixed(digits) === number.toFixed(digits);
}
console.log((1.0-0.7).isEqual(0.3)); //true

Number.MAX_VALUE和Number.MAX_SAFE_INTEGER存在的意义是什么?

安全整数不会失真。

总结

对于浮点数来说,会这些基本可以解决一般遇到的问题了。

扫描二维码关注公众号,回复: 13014398 查看本文章

引用文章

浅谈JavaScript浮点数及其运算
浮点数演示网站
前端应该知道的JavaScript浮点数和大数的原理

猜你喜欢

转载自blog.csdn.net/a519991963/article/details/114634338