Есть код, по которому можно сделать вывод, что boost_decimal не работает, как надо:
#include <iostream>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <decimal/decimal>
using namespace std;
using decimal32 = decimal::decimal32;
using boost_decimal = boost::multiprecision::cpp_dec_float_50;
std::ostream& operator<<(std::ostream& out, const decimal32& d)
{
out << decimal::decimal32_to_double(d);
return out;
}
int main()
{
decimal32 a(0.1);
auto a2 = a+a+a+a+a+a+a+a+a+a;
cout << a2 << "\n";
cout << (a2==1) << "\n";
boost_decimal b(0.1);
auto b2 = b+b+b+b+b+b+b+b+b+b;
cout << b2 << "\n";
cout << (b2==1) << "\n";
return 0;
}
Результат:
1
1
1
0
Это баг или фича?
Здравствуйте, anatoly1, Вы писали:
A>Это баг или фича?
Это норма.
0.1 в double на самом деле представлено как 0.10000000000000001.
Переменная b при инициализации получает значение 0.1000000000000000055511151231257827021181583404541015625
А сумма b2 1.000000000000000055511151231257827021181583404541015625
При сравнении (b2==1) b2 не приводится к int, а наоборот.
Если написать (static_cast<int>(b2) == 1), то результат будет true.
Ну или можно сделать так:
boost_decimal b2(1);
boost_decimal b3(10);
auto b4(b2 / b3); // честный 0.1
::std::cout << ::std::setprecision(80) << b4 << ::std::endl;
auto s2(b4+b4+b4+b4+b4+b4+b4+b4+b4+b4);
::std::cout << "sum2 " << ::std::setprecision(80) << s2 << ::std::endl;
assert(s2==1);
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, VTT, Вы писали:
VTT>Это норма.
Я в курсе, что с double буде точно так же. Для того decimal и использую, чтобы проблему решить. decimal32 нормально же работает.
PS
Выяснил, что если проинициализировать так:
boost_decimal b("0.1");
то при сравнении будет true. Но подобный подход не устраивает.
Здравствуйте, anatoly1, Вы писали:
A>Я в курсе, что с double буде точно так же. Для того decimal и использую, чтобы проблему решить. decimal32 нормально же работает.
сам себе и ответил.
если брать за начальное значение число в double которое в нем точно представить нельзя то и результат будет соответсвующим...
как вариант
boost_decimal b(1);
b /= 10;
Здравствуйте, anatoly1, Вы писали:
A>Для того decimal и использую, чтобы проблему решить. decimal32 нормально же работает.
decimal32 поддерживает 7 десятичных цифр, он округлил входящий double и все получилось красиво, хвост пропал. вики:
https://en.wikipedia.org/wiki/Decimal32_floating-point_format
cpp_dec_float_50 поддерживает 50 десятичных цифр, он достаточно точно переварил кучу знаков после запятой. в итоге получилось не 0.1
отсюда и разное поведение
как вариант, я бы предложил найти метод округления в cpp_dec_float_50 под нужную точность и задействовать его. с этими классами не работал, так что не подскажу как это сделать и возможно ли это в принципе