О точности с плавающей точкой: почему числа итераций не равны? - PullRequest
4 голосов
/ 25 июня 2011

Существуют две похожие программы Matlab, одна итерация 10 раз, а другая 11 раз.

One:

i = 0;
x = 0.0;
h = 0.1;
while x < 1.0
    i = i + 1;
    x = i * h;
    disp([i,x]);
end

Другой:

i = 0;
x = 0.0;
h = 0.1;
while x < 1.0
    i = i + 1;
    x = x + h;
    disp([i,x]);
end

Я не понимаю, почему существует разница между операцией добавления с плавающей запятой и кратным.

Ответы [ 3 ]

4 голосов
/ 25 июня 2011

Вы должны быть очень осторожны при выполнении итераций с помощью счетчиков с плавающей запятой. В качестве примера я покажу вам, что происходит в вашем случае (это Java-программа, но ваш случай должен быть таким же): нажмите здесь, чтобы запустить ее самостоятельно

double h = 0.1;
System.out.println(10*h-1.0);
System.out.println(h+h+h+h+h+h+h+h+h+h-1.0);

Он просто выводит разницу в единицу при выполнении умножения или сложения.

Поскольку представление чисел с плавающей точкой не является точным, результат выглядит следующим образом:

0.0
-1.1102230246251565E-16

Таким образом, если вы используете это как условие цикла, в последнем случае будет дополнительная итерация (одна еще не достигнута).

Попробуйте использовать переменную-счетчик i, которая является целым числом, и вы не столкнетесь с такими проблемами.

2 голосов
/ 25 июня 2011

Сравните вывод следующего:

>> fprintf('%0.20f\n', 0.1.*(1:10))
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.60000000000000009000
0.70000000000000007000
0.80000000000000004000
0.90000000000000002000
1.00000000000000000000

>> fprintf('%0.20f\n', cumsum(repmat(0.1,1,10)))
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.59999999999999998000
0.69999999999999996000
0.79999999999999993000
0.89999999999999991000
0.99999999999999989000

Также сравните с использованием оператора COLON в MATLAB:

>> fprintf('%0.20f\n', 0.1:0.1:1)
0.10000000000000001000
0.20000000000000001000
0.30000000000000004000
0.40000000000000002000
0.50000000000000000000
0.59999999999999998000
0.69999999999999996000
0.80000000000000004000
0.90000000000000002000
1.00000000000000000000

Если вы хотите увидеть 64-битное двоичное представление, используйте:

>> format hex
>> [(0.1:0.1:1)' (0.1.*(1:10))' cumsum(repmat(0.1,10,1))]
   3fb999999999999a   3fb999999999999a   3fb999999999999a
   3fc999999999999a   3fc999999999999a   3fc999999999999a
   3fd3333333333334   3fd3333333333334   3fd3333333333334
   3fd999999999999a   3fd999999999999a   3fd999999999999a
   3fe0000000000000   3fe0000000000000   3fe0000000000000
   3fe3333333333333   3fe3333333333334   3fe3333333333333
   3fe6666666666666   3fe6666666666667   3fe6666666666666
   3fe999999999999a   3fe999999999999a   3fe9999999999999
   3feccccccccccccd   3feccccccccccccd   3feccccccccccccc
   3ff0000000000000   3ff0000000000000   3fefffffffffffff

Некоторые рекомендуемые значения (связанные с MATLAB):

0 голосов
/ 25 июня 2011

Представление с плавающей точкой является точным, за исключением того, что арифметика с плавающей точкой находится в базе 2, а десятичные числа, такие как 0,1, имеют бесконечное двоичное расширение.Поскольку числа с плавающей точкой имеют конечное число битов, необходимо округлить бесконечное расширение 0,1, и при сложении накапливается ошибка округления, что приводит к расхождению.

Однако большинство операций с плавающей запятой операций являются неточными: для результатов обычно требуется больше битов точности, чем для фиксированного числа битов, поэтому ЦПУ автоматически округляет результат, чтобы соответствовать доступной точности.Как вы заметили, такие ошибки округления накапливаются в длинных цепочках вычислений и приводят иногда к огромным расхождениям между фактическим и «правильным» результатом.(«правильный» определяется как результат, полученный в арифметике с бесконечной точностью.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...