关于javascript:通用浮点数学查询

General floating-point maths query

好吧,我知道有些数字不能用二进制正确表示,就像1/3不能用十进制完全表示一样。

所以当我console.log(0.3)返回0.3但是当i console.log(0.1+0.2)返回0.30000000000000004

当简单地输出0.3时,它是如何解释错误的(如果它是的话),但是当加法发生时,它却不能解释?


假设我们用小数来表示1/3和2/3。

1
2
1/3 = 0.333
2/3 = 0.667

加上1/3+1/3:

1
1/3+1/3 = 0.333 + 0.333 = 0.666

我们没有得到2/3的近似值。把1/3四舍五入到我们可以用十进制表示的数值,并没有产生一个等于我们四舍五入2/3所得数值的一半的数值。

同样的事情也发生在二进制中。我们将0.1和0.2四舍五入到可以用二进制表示的数字,但是近似值的和与我们得到的值(如果我们接近0.3)略有不同。我们得到了更高的值,结果显示为0.30000000000000004


0.10.2的内部表示中的不精确性非常小,以至于javascript打印机在打印这些数字时忽略了它们。但当你把它们加在一起,不准确的地方就会累积起来,这就足以在结果打印出来时显示出来。


Java打印浮点数字的方式是您所看到的行为的一个重要部分:默认情况下,Java不打印浮点数字的确切值。它只打印足够的数字来精确识别正在打印的double

因此,如果将x设置为.3,则x实际上设置为0.2999999999999988897769753748434595763683319091796875。当Java打印此时,它只打印".3",因为将"3"转换为EDCOX1〔3〕,产生EDCOX1〔4〕、0.29、99、99、99、896、976、375、84、345、956、3636、33、199、9968、75的值。

使用.1.2时,这些值实际上是0.10000000000000055511151231257827021181583404541015625和0.200000000000000111022302462515655404236316680908203125。添加时(double格式),结果为0.30000000000440890850062616169452667236328125。

当您打印这个值时,Java打印"0.3000000000000000",因为它需要显示所有这些数字,以便产生一个数字,当转换回EDCOX1(3)时,它将产生0.30万×10000 044 4089209866261616945 2667 23 6328 125。

以下是有关如何打印double值的文档。它说:

How many digits must be printed for the fractional part…? There must be at least one digit to represent the fractional part, and beyond that as many, but only as many, more digits as are needed to uniquely distinguish the argument value from adjacent values of type double.


正如你所说,在基数10中,你不能准确地描述分数1/3。同样,在基2中,您不能准确地描述某些其他分数。所以,当计算机增加0.1和0.2时,实际上是增加了0.1000000000001和0.20000000003。