General floating-point maths query
好吧,我知道有些数字不能用二进制正确表示,就像1/3不能用十进制完全表示一样。
所以当我console.log(0.3)返回0.3但是当i console.log(0.1+0.2)返回0.30000000000000004
当简单地输出0.3时,它是如何解释错误的(如果它是的话),但是当加法发生时,它却不能解释?
- 删除了标记,因为这是特定于javascript的数字显示。
- @Wooble实际上显示了相同的行为,即使最近有了一些变化,在许多浮点的显示中隐藏了如此小的错误。
- 好吧,repr是这样的。str没有。
- 要想自己知道答案是什么,试着强制系统用比默认值更高的精度来表示数字。例如,尝试(在python中){:.20f}".format(0.1)。
- @Wooble在最近的版本中都是这样的,因为它们都使用了新的算法。
假设我们用小数来表示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.1和0.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。
- 但这并不能解释为什么console.log(0.1)显示0.1而不是0.10000000001。
- 当您只想发送一些东西到console.log时,没有涉及任何算法。当你加上两个浮点数时,不精确性就起作用了。
- 当它把0.1解析成一个内部值为0.10000000001`的浮点时,会产生什么不准确呢?
- @Danmullen:发送东西到console.log中涉及到一种算法。必须格式化该值,包括从double转换为十进制数字。这涉及很多算术运算。存在不准确之处:打印double值0.29999999999988897769753748434595763683319091796875时,生成"0.3"。因此,用于打印的转换会带来错误。
- 接受,但从您的示例中,我想当只打印一个数字时,可能涉及到一些舍入。当您添加浮点数(或对其执行其他算术运算)时,它们在内部表示方式中的不精确性具有累积效应。