求 0.1 到 10 的立方,这个算法有什么问题?

Finding the cubes of numbers from 0.1 to 10, what's the problem in this algorithm?

我目前正在为我的离散结构做练习作业 class,作业如下:

"下面的算法表示尝试以 0.1 的步长打印出从 0.1 到 10 的数字立方体 table。解释如果在计算机上实现该算法可能出现的问题:

x = 0.0
Repeat
    x = x + 0.1
    x_cubed = x^3
    Output x, x_cubed
    until x = 10.0

这是伪代码,所以我认为错误与语法无关。 我重写了 java 和 运行 中的代码。如果我将 (x != 10.0) 作为条件,程序将永远不会停止,因为出于某种原因 0.2 + 0.1 会导致 0.30000000000000004,这使得 x 永远不会精确地变为 10.0。但是,我不知道这是否是教授正在寻找的问题,因为它可能是 Eclipse 或 Java 问题。

有人可以帮我做这个练习吗? 谢谢!

问题是大多数时候比较浮点数是否相等 (until x = 10.0) 会 not work as one would expect。在您的特定情况下,一种解决方案是在循环中使用整数,并在需要时使用另一个浮点数。

int i = 0
float x = 0.0
Repeat
    i = i + 1
    x = x + 0.1
    x_cubed = x^3
    Output x, x_cubed
    until i = 100

辩证法说得对:比较计算出的浮点数是否相等是危险的。由于某些数字不能完全以二为底表示(例如 0.1),因此这些数字只能近似正确。

您可以按照他的建议使用整数,但我会做进一步的调整:考虑计算 x[n+1] = dx * 而不是计算 x[n+1] = x[n] + dx我[n+1]。换句话说,不要使用重复的加法(随着时间的推移可能会累积很大的错误);相反,从迭代的整数和浮点步长(在本例中为 0.1)计算每次迭代的 x de novo 的值。这不会以相同的方式随着时间的推移累积错误。我鼓励您通过比较每一步重复加法与直接乘法获得的百万分之一的值来尝试一下。

编辑:我有空闲时间所以我决定自己做这个测试。

<html>
 <head>
  <title>
   Floating Point Test
  </title>
 </head>
 <body>
  <input type="button" id="btnRun" value="Run" onclick="run();" />
  <br/>
  <textarea id="txtOutput" rows=20 cols=50></textarea>
  <script language="javascript">
    function run() {
        var add = 0.0;
        var mul = 0.0;
        var i = 0;
        var dx = 0.1;
        var lastPower = 1;
        var output = "";
        for (i = 0; i < 1000000000; i++) {
            add = add + dx;
            mul = dx * (i + 1);
            if (i + 1 >= lastPower) {
                output += "i=" + i + ", add=" + add + ", mul=" + mul + "\n";
                lastPower *= 10;
            }
        }
        document.getElementById("txtOutput").value = output;
    }
  </script> 
 </body>
</html>

输出如下所示:

i=0, add=0.1, mul=0.1
i=9, add=0.9999999999999999, mul=1
i=99, add=9.99999999999998, mul=10
i=999, add=99.9999999999986, mul=100
i=9999, add=1000.0000000001588, mul=1000
i=99999, add=10000.000000018848, mul=10000
i=999999, add=100000.00000133288, mul=100000
i=9999999, add=999999.9998389754, mul=1000000
i=99999999, add=9999999.98112945, mul=10000000
i=999999999, add=99999998.74541782, mul=100000000