Нахождение кубов чисел от 0,1 до 10, в чем проблема в этом алгоритме? - PullRequest
3 голосов
/ 04 февраля 2020

В настоящее время я выполняю практическое задание для своего класса Discrete Structures, и назначение следующее:

"Приведенный ниже алгоритм представляет собой попытку распечатать таблицу кубов чисел от 0,1 до 10 с шагом 0.1. Объясните проблему, которая может возникнуть, если алгоритм реализован на компьютере:

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. Однако Я не знаю, ищет ли это проблему профессор, так как это может быть проблема Затмения или Java.

Может кто-нибудь помочь мне с этим упражнением? Спасибо!

Ответы [ 2 ]

4 голосов
/ 04 февраля 2020

Диалектик имеет право: сравнивать вычисленные поплавки на равенство опасно. Из-за того, что некоторые числа не являются полностью представимыми в базе два (например, 0,1), они будут только приблизительно правильными.

Вы можете использовать целые числа, как он предлагает, но я бы сделал еще одну поправку: скорее чем вычислять x [n + 1] = x [n] + dx, рассмотрим вычисление x [n + 1] = dx * i [n + 1]. Другими словами, не используйте повторное добавление (которое может накапливать большие ошибки со временем); вместо этого вычисляйте значение x de novo на каждой итерации из целого числа, которое итерируется, и шага с плавающей запятой (в данном случае 0,1). Это не будет накапливать ошибки с течением времени таким же образом. Я рекомендую вам попробовать это, сравнивая миллионное значение, полученное при повторном сложении, с прямым умножением на каждом шаге.

РЕДАКТИРОВАТЬ: У меня была свободная минутка, поэтому я решил провести этот тест самостоятельно.

<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
2 голосов
/ 04 февраля 2020

Проблема в том, что в большинстве случаев сравнение числа с плавающей точкой на равенство (until x = 10.0) не будет работать так, как можно было бы ожидать . В вашем конкретном случае c одним из решений было бы использование целого числа для l oop и другого числа с плавающей запятой при необходимости.

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
...