为什么在Javascript中相加两个小数会产生错误的结果?

82

可能重复:
JavaScript的Math是有问题的吗?

为什么JS会在这个简单的数学运算中出错?

console.log(.1 + .2)  // 0.3000000000000004
console.log(.3 + .6)  // 0.8999999999999999

第一个示例比正确结果大,而第二个示例则小。怎么解决这个问题?在执行操作之前,必须始终将小数转换为整数吗?我只需要担心加法吗(在我的测试中,*和/似乎没有相同的问题)?
我已经在许多地方寻找答案。一些教程(例如购物车表单)假装这个问题不存在,只是将值相加。行家提供了各种数学函数的复杂程序或提到JS“效果不佳”,但我还没有看到过解释。

请查看此问题的答案:https://dev59.com/G3RB5IYBdhLWcg3wj36c - Mark Bell
可能是成千上万个与编程有关的论坛中的重复问题。 - Michael Borgwardt
1
应该为包含字符串9999999的问题设置一个特殊处理程序。 - starblue
没错!这应该在每个JS快速入门指南以及其他任何地方都有提到。每当有人写下“这是如何在JavaScript中进行数学计算的”,他们都应该附上一个巨大的“顺便说一句:你无法进行简单的十进制数学计算!” - Greg Perham
@Greg: PHP 手册有这个内容:http://www.php.net/manual/zh/language.types.float.php - Michael Borgwardt
显示剩余3条评论
5个回答

45

这不是JS问题,而是一个更普遍的计算机问题。浮点数无法正确存储所有十进制数字,因为它们使用二进制进行存储。 例如:

0.5 is store as b0.1 
but 0.1 = 1/10 so it's 1/16 + (1/10-1/16) = 1/16 + 0.0375
0.0375 = 1/32 + (0.0375-1/32) = 1/32 + 00625 ... etc

so in binary 0.1 is 0.00011... 

但这是永无止境的。不过,计算机必须在某个时刻停止。所以如果在我们的例子中,在0.00011处停止,我们得到的是0.09375而不是0.1。

总之,重点是,这并不取决于编程语言,而是取决于计算机本身。取决于编程语言的是如何显示数字。通常,编程语言会将数字四舍五入为一个可以接受的表示方式。显然,JavaScript不会这样做。

因此,你需要做的(内存中的数字已经足够准确)就是告诉JavaScript在将数字转换为文本时“好好”地四舍五入。

你可以尝试使用 sprintf 函数,它可以让你精细控制数字的显示方式。


22

来自浮点数指南:

为什么我的数字,像0.1 + 0.2这样的数字不会加起来得到一个漂亮的0.3,而是会得到一个奇怪的结果,比如0.30000000000000004?

因为在计算机内部,使用一种格式(二进制浮点数)无法准确地表示像0.1、0.2或0.3这样的数字。

当代码被编译或解释时,“0.1”已经被舍入到该格式中最接近的数字,这会导致小的舍入误差,甚至在计算发生之前就已经出现了。

该网站提供了详细的解释以及如何解决该问题的信息(以及如何确定在您的情况下是否存在问题)。


更简单的答案。 - haMzox
有关此内容的更多信息,请访问http://floating-point-gui.de/basic/。 - Pardeep Jain

8
这不仅仅是JavaScript的限制,而是所有浮点运算都一样。问题在于0.1、0.2和0.3在JavaScript(或C或Java等)中不能被准确地表示为浮点数。因此你看到的输出结果是由于这种不准确性造成的。
特别地,只有某些二次幂之和才能够被准确地表示。例如0.5=0.1b=2^(-1),0.25=0.01b=2^(-2),0.75=0.11b=(2^-1+2^-2)都是可以的。但是1/10=0.000110001100011..b只能够被表示为二次幂的无穷和,而编程语言会在某个位置截断这个无穷和。正是这个截断导致了这些微小的误差。

5

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接