javascript中0.1 + 0.2 != 0.3?

0 1+0 2 等于0 3吗?相信拿着这条题目随便问一个高年级的小学生,他们都会毫不犹豫都回答:相等。是的,相等是正常的,这是常识。但

0.1+0.2

等于0.3吗?相信拿着这条题目随便问一个高年级的小学生,他们都会毫不犹豫都回答:相等。是的,相等是正常的,这是常识。但是都说实践是检验真理的唯一标准,拿这道简单的算术题用javascript在chrome控制台试验一下:

结果令人大跌眼镜,在控制台输入 0.1+0.2 == 0.3

返回的结果竟然是false!!!!我们输入 0.1+0.2

,看看结果,竟然是 0.30000000000000004

这是为什么呢?在《Javascript权威指南》中有提到,JS是不区分整数和浮点数的,JS采用的是IEEE 754标准定义的64位浮点格式表示数字,所以JS中的所有数字都是浮点数。按照JS的数字格式,整数有的范围是 -2^53 ~ 2^53

,而且只能表示有限个浮点数,能表示的个数为 2^64 − 2^53 + 3

个。至于为什么是这个范围,可以具体看看《 JavaScript 中的数字

》这篇文章也解下。而我们都知道,浮点数的个数是无限的,这就导致了JS不能精确表达所有的浮点数,而只能是一个近似值。

那怎样才能比较 0.1+0.2 == 0.3

呢?既然浮点数是一个近似值,那我们可以认定在某个可以接受的精度范围内,他们是相等的。因此可以定义一个比较函数来比较浮点数。

function isFloatEqual(f1,f2,digits) {

return f1.toFixed(digits) === f2.toFixed(digits);

}

isFloatEqual(0.1+0.2,0.3,10); // 返回true

可以看到,这时再比较 0.1+0.2

就与0.3相等了。这种比较,其实是字符串的比较,toFixed方法,返回的是一个字符串。可以在控制台中输入:

0.1.toFixed(1)+0.2.toFixed(1)

你会发现,返回的结果是"0.10.2"

那除了上面的方法外,能不能让JS在做加减法的时候精确一点呢?

我们知道,只要在 -2^53 ~ 2^53

的范围内,JS做整数的加减运算是精确的,那么我们是不是可以将浮点数转换为整数,再进行运算呢?按照这个思路,在《 浅谈JavaScript浮点数及其运算

》这篇文章中,提供了一种方法,将代码粘贴如下:

function accAdd(arg1,arg2){

var r1,r2,m;

try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}

try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}

m=Math.pow(10,Math.max(r1,r2))

return (arg1*m+arg2*m)/m

}

这种方法是先计算出两个浮点数的小数位数n,两个参数再分别与 10^n

(放大倍数)相乘,以达到对两个参数取整的目的,再用整数来进行相加运算,加完后除掉放大的倍数就可以得出结果了。

现在用 accAdd(0.1,0.2)

,返回的结果是 0.3

了,但是评论里面马上有人提出 accAdd(2.22,0.1)

的结果不是 2.32

,而是 2.3200000000000003

。原来在做 arg1*m

这一步时,依旧是浮点数运算,所以返回的结果不一定是整数,依旧是浮点数。

我看到作者在做减法的时候用了toFixed(),如果用toFixed(n)是不是就可以了呢?来试一下,函数改造成这样:

function accAdd(arg1,arg2){

var r1,r2,n,m;

try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}

try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}

n = Math.max(r1,r2);

m=Math.pow(10,n);

return ((arg1*m+arg2*m)/m).toFixed(n)

}

这次再调用 accAdd(2.22,0.1)

时,返回的是 2.32

了,完美!

但是手贱试了下 accAdd(2.22,0.08)

,返回的结果是 2.30

,而我期望返回的结果是 2.3

。上文已经提到过,toFixed返回的是一个字符串,所以用toFixed返回 2.30

看来是正常的了。那如果要返回 2.3

要怎样做呢?

其实很简单,用parseInt将 arg1*m

转换为整数就可以了。

function accAdd(arg1,arg2){

var r1,r2,m;

try{r1=arg1.toString().split(".")[1].length}catch(e){r1=0}

try{r2=arg2.toString().split(".")[1].length}catch(e){r2=0}

m=Math.pow(10,Math.max(r1,r2))

return (parseInt(arg1*m,10)+parseInt(arg2*m,10)/m

}

未登录用户
全部评论0
到底啦