Чтобы получить правильные результаты, не устанавливайте точность выше, чем доступно для этого числового типа:
#include <iostream>
#include <limits>
int main()
{
double a = 0.3;
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << a << std::endl;
double b = 0;
for (char i = 1; i <= 50; i++) {
b = b + a;
};
std::cout.precision(std::numeric_limits<double>::digits10);
std::cout << b << std::endl;
}
Хотя, если этот цикл выполняется для 5000 итераций вместо 50, накопленная ошибка будет отображаться даже при таком подходе - это как работают числа с плавающей запятой.
Чтобы получить "правильный" результат, попробуйте
Список библиотек арифметики произвольной точности из Википедии: http://en.wikipedia.org/wiki/Arbitrary-precision
or
Компьютеры хранят числа с плавающей запятой в двоичном, а не десятичном виде.
Многие числа, которые выглядят обычными в десятичной системе счисления, например 0,3, не имеют точного представления конечной длины в двоичной системе счисления.
Поэтому компилятор выбирает ближайшее число, которое имеет точное двоичное представление, точно так же, как вы пишете 0.33333
для 1⁄3
.
Если вы складываете много чисел с плавающей точкой, эти крошечные различия суммируются, и вы получаете неожиданные результаты.
Дело не в том, что оно больше или меньше, просто физически невозможно хранить "0.3" как точное значение внутри двоичного числа с плавающей точкой.
Способ получить "правильный" результат - не отображать 20 знаков после запятой.
Почему?
Поскольку числа с плавающей запятой хранятся в двоичном формате, в котором 0,3 равно 0,01001100110011001 ... повторение точно так же, как 1/3 равно 0,333333 ... повторение в десятичном формате. Когда вы пишете 0,3
, вы фактически получаете 0,299999999999999988897769753748434595763683319091796875 (бесконечное двоичное представление, округленное до 53 значащих цифр).
Имейте в виду, что для приложений, для которых предназначена плавающая точка, не проблема, что вы не можете точно представить 0,3. Плавающая точка была разработана для использования с:
Для которых двоично-десятичные преобразования в значительной степени не имеют значения по сравнению с другими источниками ошибок.
Теперь, если вы пишете финансовое программное обеспечение, для которого 0,30 доллара означает ровно 0,30 доллара, это другое. Существуют классы десятичной арифметики, предназначенные для этой ситуации.
А как в этом случае получить правильный результат?
Обычно достаточно ограничить точность до 15 значащих цифр, чтобы скрыть «шумные» цифры. Если вам действительно не нужен точный ответ, это обычно лучший подход.