Неожиданный вывод при добавлении двух чисел с плавающей точкой
Я написал следующий код C++:
float a, b;
int c;
a = 8.6;
b = 1.4;
c = a + b;
printf("%d\n", c);
Выход 10
,
Но когда я запускаю следующий код:
float a, b;
int c;
a = 8.7;
b = 1.3;
c = a + b;
printf("%d\n", c);
Выход 9
,
В чем разница между ними, так как они дают разные результаты?
3 ответа
Там нет такого числа, как 8,7 или 1,3 в плавающей запятой. Есть число 10, число -6,5 и число 0,96044921875... но нет 8,7 или 1,3.
В лучшем случае ваш компьютер может округлить 8,7 до ближайшего числа с плавающей запятой, а также округлить до 1,3 до ближайшего числа с плавающей запятой. Компьютер добавляет эти округленные числа друг к другу, а затем округляет результат.
Не используйте числа с плавающей запятой для денег.
#include <stdio.h>
int main(int argc, char *argv[])
{
float a = 8.7, b = 1.3;
printf("Looks like: %.1f + %.1f = %.1f\n", a, b, a+b);
printf("The truth: %.20f + %.20f = %.20f\n", a, b, a+b);
return 0;
}
На компьютере x86 GCC/Linux я получаю результат:
Похоже: 8,7 + 1,3 = 10,0 Правда: 8.69999980926513671875 + 1.29999995231628417969 = 9.99999976158142089844
На компьютере PPC GCC/OS X я получаю результат:
Похоже: 8,7 + 1,3 = 10,0 Правда: 8,69999980926513671875 + 1,29999995231628417969 = 10,00000000000000000000
Обратите внимание, как 8.7 и 1.3 оба округляются в этом конкретном случае. Если вы выбрали округленные числа, вы можете увидеть число больше 10 с правой стороны.
Посмотрите, что каждый компьютерный ученый должен знать об арифметике с плавающей точкой, автор Дэвид Голдберг ( ссылка).
Числа с плавающей точкой не совпадают с действительными числами, и их поведение совершенно иное.
Вещественные числа бесконечны, в то время как числа с плавающей запятой конечны и могут представлять только небольшое подмножество всех возможных действительных чисел.
Поскольку не все действительные числа могут быть представлены в виде чисел с плавающей запятой, присваивание или операция с плавающей запятой может дать вам результаты, немного отличающиеся от тех, которые выполняются в пространстве действительных чисел.
Посмотрите запись в Википедии о плавающей точке для ознакомления. Раздел о точности с плавающей запятой особенно интересен и дает другие примеры, подобные вашему.
Там нет реальной разницы между ними. Они оба ведут себя непредсказуемым образом.
То, что вы делаете, равносильно тому, чтобы дважды подбросить монетку и спросить, что вы сделали по-другому, чтобы получить головы один раз, а другие - хвост. Дело не в том, что вы сделали что-то другое, а в том, что происходит, когда вы подбрасываете монеты.
Если вы попросите человека добавить одну треть и две трети, используя шестизначную десятичную точность, а затем округлить до целого числа, вы можете получить 0, а можете получить 1. Это будет зависеть от того, будут ли они представлять 2/3 как "0,666666". "или"0.6666667", и они оба приемлемы. Таким образом, и 0 и 1 являются приемлемыми ответами. Если вы не готовы принять любой ответ, не задавайте такой вопрос.