是什么造成了这个奇怪的Mathematica结果?

时间:2011-03-03 19:07:46

标签: wolfram-mathematica

我遇到了Mathematica 8中的一个错误。我在网上找不到任何与之相关的内容,但我承认我不确定要搜索什么。

如果我运行此声明:

0.05 + .10 /. {0.15 -> "pass"}
1.04 + .10 /. {1.14 -> "pass"}
1.05 + .10 /. {1.15 -> "pass"}
1.15 /. {1.15 -> "pass"}

我得到了这个输出:

pass

pass

1.15

pass

我只是忽略了什么?

编辑:在阅读下面的有用讨论后,我将调度表更改为使用了哪个语句:

f[x_] := Which[x == 1.05, -1.709847, x == 1.10, -1.373823, 
  x == 1.15, -1.119214, x == 1.20, -0.9160143, x == 1.25, -0.7470223, x == 1.30, -0.6015966]

这似乎可以解决问题。

3 个答案:

答案 0 :(得分:14)

欢迎来到机器精度的世界。如果你仔细研究1.05 + 10和1.15,你会发现它们不完全相同:

1.05 + .10 // FullForm

==> 1.1500000000000001`

1.15 // FullForm

==> 1.15`

答案 1 :(得分:6)

除了在使用MachinePrecision时产生小错误外,相同的浮点计算在一天中的不同时间会产生稍微不同的结果。这不是一个错误,而是现代硬件浮点架构如何工作的by-product

这意味着您不应使用ReplaceAll之类的操作,这些操作取决于对MachinePrecision数字的确切值的了解。使用==(和===)可能没问题,因为它们会忽略MachinePrecision个数字的最后7个(分别为1个)二进制数字。

使用Mathematica算法应该给出精确的结果,无论何时,您可以将它用于您的示例,如下(10位有效数字)

0.05`10 + .10`10 /. {0.15`10 -> "pass"}
1.04`10 + .10`10 /. {1.14`10 -> "pass"}
1.05`10 + .10`10 /. {1.15`10 -> "pass"}
1.15`10 /. {1.15`10 -> "pass"}

更新What Every Computer Scientist Should Know About Floating-Point Arithmetic提供了有关浮点运算的更多注意事项。例如,第80页给出了IEEE 754的不同实现如何给出略微不同的结果的示例,即使是符合标准的

答案 2 :(得分:4)

您的替换只适用于完全匹配,而您的While语句使用Equal。您也可以使用Equal来使基于规则的方法有效。

0.05 + .10 /. {x_ /; x == 0.15 -> "pass"}
1.04 + .10 /. {x_ /; x == 1.14 -> "pass"}
1.05 + .10 /. {x_ /; x == 1.15 -> "pass"}
1.15 /. {x_ /; x == 1.15 -> "pass"}