javascript 的 0.1 + 0.2 问题引出的 Number 专题

318 阅读2分钟

面试中,我们被问到过, 0.1 + 0.2 是否等于 0.3 这样的问题, 从而引出 javascript 中 number 运算精度问题. 因此我们来彻底 剖析下 js 中的 Number 类型

Number 资料

1. 整数

js 没有真正意义上的整数, 所有的 number 采用 IEEE 754 格式来表示, 也就是 '浮点数', 所以 42.0 也是整数, 他等同于 '整数' 42.

js 中的 '整数' 就是没有小数(小数位为 0 的除外)的十进制数

1.1 Number精度不准:

因为 js 的数字表示方式, 无论是 int ,float 他们都是 Number 类型, 然而 Number 类型是用 IEEE 754 的方案去定义的. 凡是采用这种定义的都会有 精度不准的问题

1.2 IEEE 754

由于javascript采用 IEEE754, 即 采用二进制浮点数,都并不是十分的精确 所以, 0.1 和 0.2 其实都不是十分精确的值, 所以 0.1+ 0.2 得到的不是 0.3

1.3 何为 IEEE 754 会精度不准

2. NaN

  • NaN 不会等于自身
console.log(NaN!==NaN) // true

3. 特殊等式

Object.is() 可以用来判断两个值是否绝对相等, 是否是同一值, 但是其效率远远没有 ===

	if(!Object.is){
    	Object.is = function(v1, v2){
        	// 判断是否为 -0;
            if(v1===0 && v2 ===0){
            	// 因为 -0 和 0 都 === 0
                // 1 / -0 = -Infinity
                // 1 / 0 = Infinity
            	return  1/v1 === 1/v2; 
            }
            // 判断 NaN
            if(v1 !== v1 ){
      			return v2 !== v2;  // NaN !== NaN 返回 true
            }
            // 其他情况
            return v1 ===v2;
        }
    }




Number 类型的相关提问:

  1. 如何才能让 0.1 + 0.2 === 0.3 这里我们采用一个machine epsilon 机器精度, 对于 js 来说, 应该是 2 ^ -52, 在 es6 之后为 Number.EPSILON
function numbersCloseEnough(a ,b){
	return Math.abs(n1- n2)< Number.EPSILON;
}
// 如果为 true, 我们可以认为他们就是同一个值
let a = 0.1+ 0.2;
let  b= 0.3;
numbersCloseEnough(a,b); //  true
numbersClaseEnough(0.0000001, 0.0000002); // false

  1. 42.000 是不是整数
Number.isInteger(42.000) // true

在 js 中对于整数的定义不是他是否有小数点, 或者小数点之后有几位, 而是我们需要关心的是, 他除以自身得到的模是否为 0