Почему при умножении чисел с плавающей запятой ошибок нет?
Мне нужно некоторое уточнение о математике с плавающей запятой.
Я написал некоторый код для обучения purpouses:
#include "stdio.h"
int main (int argc, char const *argv[])
{
int i;
double a=1.0/10.0;
double sum=0;
for(i = 0; i < 10; ++i)
sum+=a;
printf("%.17G\n", 10*a );
printf("%d\n", (10*a == 1.0) );
printf("%.17G\n", sum );
printf("%d\n", (sum == 1.0) );
return 0;
}
и вывод, который он дает:
1
1
0.99999999999999989
0
Почему (сумма == 1.0) - ложно, довольно понятно, но почему умножение дает правильный ответ без ошибки?
Спасибо.
Ответы
Ответ 1
При выполнении повторного добавления происходит 9 округлений: первый результат a+a
всегда точно представлен, но после этого дальнейшие дополнения неточны, поскольку показатели базового уровня слагаемых не равны.
При выполнении умножения существует только одно округление, и это дает вам результат, который вы хотели.
Ответ 2
Если вы посмотрите на фактический язык ассемблера, вы обнаружите, что компилятор не генерирует одно умножение, о котором вы просите. Вместо этого он просто предоставляет фактическое значение. Если вы отключите оптимизацию, вы можете получить ожидаемые результаты (если ваш компилятор в любом случае не оптимизирует это).
Ответ 3
У вас много проблем с вашим кодом.
плавающая точка на компьютере - это база 2. Вы не можете точно представлять 0,1 в плавающей запятой (точно так же, как вы не можете представить 1/3 в базе 10, сравнивая яблоки с яблоками), поэтому любые другие предположения после этого (умножьте на 10 и ожидайте это, например, один). Плохо.
Однократное умножение в 10 раз 0.1 только однократно приводит к ошибке. Многократные добавления приводят к ошибке в 10 раз. Округление фиксирует 10 раз 0,1 при преобразовании в целое, что делает его похожим на то, что он действительно работал. Округление является еще одной особенностью плавающей запятой IEEE, режим округления, используемый по умолчанию в вашей системе, а также то, что 1/10-й снова стал снова, в основном сделал однократное умножение, похоже, что оно сработало.
следующая проблема заключается в том, что вы делаете равные сравнения с плавающей точкой, и я предполагаю, что имею какое-то ожидание. dont использовать equals на float, period. Конечно, не с такими цифрами, которые не могут быть представлены точно в плавающей точке.
попробуйте число, например, 1/16th или 1/8th вместо 1/10th...