目的:了解题目描述的问题
- 答案: 不等于。
- 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.运算类
- 取精度(使用toFixed解决(注意: 1.005.toFixed(2) === 1.00,而不是1.01)
- 字符串相加。
- 三方库使用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个符号位+11个指数位+52个尾数位
- 最大值和最小值。
- 安全最大值和安全最小值。
- 转换公式
注意
为什么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存在的意义是什么?
安全整数不会失真。
总结
对于浮点数来说,会这些基本可以解决一般遇到的问题了。