Неожиданный вывод при добавлении двух чисел с плавающей точкой

Я написал следующий код 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 являются приемлемыми ответами. Если вы не готовы принять любой ответ, не задавайте такой вопрос.

Другие вопросы по тегам