考虑以下代码:

0.1 + 0.2 == 0.3  ->  false
0.1 + 0.2         ->  0.30000000000000004

为什么会出现这些错误?


当前回答

除了其他正确答案之外,您可能还需要考虑缩放值以避免浮点运算的问题。

例如:

var result = 1.0 + 2.0;     // result === 3.0 returns true

…而不是:

var result = 0.1 + 0.2;     // result === 0.3 returns false

在JavaScript中,表达式0.1+0.2===0.3返回false,但幸运的是,浮点中的整数运算是精确的,因此可以通过缩放来避免十进制表示错误。

作为一个实际的例子,为了避免精度至关重要的浮点问题,建议1将钱作为一个整数来处理:2550美分而不是25.50美元。


1 Douglas Crockford:JavaScript:好的部分:附录A——糟糕的部分(第105页)。

其他回答

它被打破的方式与你在小学学习并每天使用的十进制(以10为基础)表示法完全相同,只是以2为基础。

要理解,请考虑将1/3表示为十进制值。这是不可能做到的!世界将在你写完小数点后的3之前结束,所以我们写了一些地方,认为它足够准确。

以同样的方式,1/10(十进制0.1)不能以2为基数(二进制)精确地表示为“十进制”值;小数点后的重复模式将永远持续下去。该值不精确,因此无法使用常规浮点方法对其进行精确计算。与基数10一样,还有其他值也显示了这个问题。

浮点舍入错误。从每个计算机科学家应该知道的浮点运算:

将无限多的实数压缩成有限位数需要近似表示。虽然有无限多的整数,但在大多数程序中,整数计算的结果可以存储在32位中。相反,给定任何固定位数,大多数使用实数的计算将产生无法使用那么多位数精确表示的量。因此,浮点计算的结果必须经常舍入,以适应其有限表示。这种舍入误差是浮点计算的特征。

浮点舍入错误。由于缺少5的素因子,0.1在基-2中不能像在基-10中那样精确地表示。正如1/3以十进制表示需要无限位数,但以3为基数表示为“0.1”,0.1以2为基数表示,而以10为基数不表示。计算机没有无限的内存。

我可以补充一下吗;人们总是认为这是一个计算机问题,但如果你用手(以10为基数)计算,你就不能得到(1/3+1/3=2/3)=真,除非你有无穷大可以将0.333…加到0.333……就像(1/10+2/10)一样==基数2的3/10问题,您将其截断为0.333+0.333=0.666,并可能将其舍入为0.667,这在技术上也是不准确的。

用三进制数,三分之三不是问题——也许有人会问为什么你的十进制数学被打破了。。。

我的解决方法:

function add(a, b, precision) {
    var x = Math.pow(10, precision || 2);
    return (Math.round(a * x) + Math.round(b * x)) / x;
}

精度是指在加法过程中要保留小数点后的位数。