js精度问题

682 阅读1分钟

原因

二进制浮点数最大的问题(不仅JavaScript,所有遵循IEEE 754规范的语言都是如此),是会出现如下情况:

0.1 + 0.2 === 0.3; // false

从数学角度来说,上面的条件判断应该为true,可结果为什么是false呢?简单来说,二进制浮点数中的0.10.2并不是十分精确,它们相加的结果并非刚好等于0.3,而是一个比较接近的数字0.30000000000000004,所以条件判断结果为false。

判断两个数是否相等

最常见的方法是设置一个误差范围值,通常称为“机器精度”(machine epsilon), 对JavaScript的数字来说,这个值通常是2^-52 (2.220446049250313e-16)。从ES6开始,该值定义在Number.EPSILON中,我们可以直接拿来用,也可以为ES6之前的版本写

//polyfill:
if (!Number.EPSILON) {
	Number.EPSILON = Math.pow(2,-52);
}

可以使用Number.EPSILON来比较两个数字是否相等(在指定的误差范围内)

function numbersCloseEnoughToEqual(n1,n2) {
	return Math.abs( n1 - n2 ) < Number.EPSILON; 
} 
var a = 0.1 + 0.2; 
var b = 0.3; 
numbersCloseEnoughToEqual( a, b );//true
numbersCloseEnoughToEqual( 0.0000001, 0.0000002 );//false

能够呈现的最大浮点数大约是1.798e+308(这是一个相当大的数字),它定义在Number.MAX_VALUE中。最小浮点数定义在Number.MIN_VALUE中,大约是5e-324,它不是负数,但无限接近于0

使用math.js处理运算

github.com/josdejong/m…

判断是否是整数

ES6语法 Number.isInteger()

polyfill写法

if (!Number.isInteger) {
	Number.isInteger = function(num) {
		return typeof num == "number" && num % 1 == 0;
  	} 
}

是否是安全的整数 Number.isSafeInteger()

判断是否是数字

首先需要理解:typeof NaN == "number"

ES6语法

Number.isNaN(123)	 // false
Number.isNaN("123")  // false
Number.isNaN("abc")  // false
Number.isNaN(1/"abc")// true
Number.isNaN(1/0)	 // false 因为1/0是Infinity正无穷大,还是数字类型

ES5写法

isNaN(123)//false
isNaN("123")//false
isNaN("abc")//true
isNaN(1/"abc")//true
isNaN(1/0)//false

还可以使用ES6语法:Object.is(num,NaN)

判断是否是有限值

isFinite() 判断被传入的参数值是否为一个有限数值(finite number)

isFinite()可能会把参数转为一个数字,Number.isFinite()不会把参数转为数值

如果参数是 NaN,正无穷大或者负无穷大,会返回false,其他返回 true。

示例

isFinite(Infinity);  // false
isFinite(NaN);       // false
isFinite(-Infinity); // false

isFinite(0);         // true
isFinite("0");       // true
isFinite(1/0);		 // false
isFinite(null);      // true
isFinite(undefined); // false

ES6语法 Number.isFinite()

Number.isFinite(0);         // true
Number.isFinite("0");       // false
Number.isFinite(1/0);		// false
Number.isFinite(null);      // false
Number.isFinite(undefined);	// false

总结

判断是否是非法数字使用Number.isNaN()

保证数字可运算使用Number.isFinite()