Я пытаюсь это:
std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;
и ожидаем, что результат будет:
0.0009
Но вывод:
0.00089999999999999998
Версия g ++: 5.4.0, версия Boost: 1.66
Что я могу сделать, чтобы напечатать то, что ему дали.
Вы Можно фактически переопределяет точность по умолчанию:
#include <boost/lexical_cast.hpp>
#ifdef BOOST_LCAST_NO_COMPILE_TIME_PRECISION
# error unsupported
#endif
template <> struct boost::detail::lcast_precision<double> : std::integral_constant<unsigned, 5> { };
#include <string>
#include <iostream>
int main() {
std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;
}
Печать
0.0009
Тем не менее, это не поддерживается (detail::
) и не гибкий (все парные теперь выйдут таким образом).
Проблема заключается в потере точности преобразования из десятичного представления в двоичное представление. Вместо этого используйте десятичное представление с плавающей точкой:
#include <boost/lexical_cast.hpp>
#include <boost/multiprecision/cpp_dec_float.hpp>
#include <string>
#include <iostream>
using Double = boost::multiprecision::cpp_dec_float_50;
int main() {
Double x("0.009"),
y = x*2,
z = x/77;
for (Double v : { x, y, z }) {
std::cout << boost::lexical_cast<std::string>(v) << "\n";
std::cout << v << "\n";
}
}
Печать
0.009
0.009
0.018
0.018
0.000116883
0.000116883
boost::lexical_cast
не позволяет указывать точность при преобразовании числа с плавающей запятой в его строковое представление. От документация
Для более сложных преобразований, например, в тех случаях, когда точность или форматирование требуют более жесткого контроля, чем предлагается по умолчанию
lexical_cast
, обычныйstd::stringstream
подход рекомендуется.
Так что вы могли бы использовать stringstream
double d = 0.0009;
std::ostringstream ss;
ss << std::setprecision(4) << d;
std::cout << ss.str() << '\n';
Или другой вариант заключается в использовании boost::format
библиотека.
std::string s = (boost::format("%1$.4f") % d).str();
std::cout << s << '\n';
0.0009
является плавающим литералом двойной точности со значением IEEE754
0.00089999999999999997536692664112933925935067236423492431640625
Это то что boost::lexical_cast<std::string>
видит как параметр функции. И настройка точности по умолчанию в cout
форматер округляет до 17 значащей цифры:
0.00089999999999999998
Действительно, если вы хотите точно десятичный точности, затем используйте десятичный тип (Boost имеет один) или работайте в целых числах и склейте в десятичном разделителе самостоятельно. Но в вашем случае, учитывая, что вы просто выводите число без сложных вычислений, округление до 15-го значимого числа даст желаемый эффект: введите
std::setprecision(15)
в выходной поток.