Более высокая точность с плавающей запятой с использованием boost lib (больше 16 цифр)
Я выполняю симуляцию физических экспериментов, поэтому мне нужна действительно высокая точность с плавающей запятой (более 16 цифр). Я использую Boost.Multiprecision, однако я не могу получить точность выше 16 цифр, что бы я ни пытался. Я запускаю симуляцию с C++ и компилятором eclipse, например:
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
void main()
{
cpp_dec_float_50 my_num= cpp_dec_float_50(0.123456789123456789123456789);
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
Выход:
0.12345678912345678379658409085095627233386039733887
^
Но это должно быть:
0.123456789123456789123456789
Как видите, после 16 цифр это неверно. Зачем?
2 ответа
Ваша проблема здесь:
cpp_dec_float_50 my_num = cpp_dec_float_50(0.123456789123456789123456789);
^ // This number is a double!
Компилятор не использует литералы с плавающей точкой произвольной точности, а вместо этого использует двойные значения IEEE-754, которые имеют конечную точность. В этом случае ближайший double
на число, которое вы написали:
0.1234567891234567837965840908509562723338603973388671875
И печать его с точностью до 50-го знака дает результат, который вы наблюдаете.
То, что вы хотите, это вместо этого построить ваш плавающий произвольной точности из строки ( демо):
#include <boost/math/constants/constants.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <iostream>
#include <limits>
using boost::multiprecision::cpp_dec_float_50;
int main() {
cpp_dec_float_50 my_num = cpp_dec_float_50("0.123456789123456789123456789");
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::digits10);
std::cout << my_num << std::endl;
}
Выход:
0.123456789123456789123456789
Проблема в том, что компилятор C++ при компиляции преобразует числа в двойные (я также узнал об этом некоторое время назад). Вы должны использовать специальные функции для обработки большего количества десятичных знаков. Посмотрите документацию Boost или другие ответы здесь на SO для примеров.
Тем не менее, почти невозможно, чтобы была какая-то реальная потребность в такой высокой точности. Если вы теряете точность, вы должны рассмотреть другие алгоритмы с плавающей запятой вместо того, чтобы слепо увеличивать число десятичных дробей.