повысить лексическое приведение к строке, что дает недопустимые результаты

Я пытаюсь это:

std::cout << boost::lexical_cast<std::string>(0.0009) << std::endl;

и ожидаем, что результат будет:

0.0009

Но вывод:

0.00089999999999999998

Версия g ++: 5.4.0, версия Boost: 1.66

Что я могу сделать, чтобы напечатать то, что ему дали.

3

Решение

Вы Можно фактически переопределяет точность по умолчанию:

Жить на Колиру

#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
2

Другие решения

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,

3

0.0009 является плавающим литералом двойной точности со значением IEEE754

0.00089999999999999997536692664112933925935067236423492431640625

Это то что boost::lexical_cast<std::string> видит как параметр функции. И настройка точности по умолчанию в cout форматер округляет до 17 значащей цифры:

0.00089999999999999998

Действительно, если вы хотите точно десятичный точности, затем используйте десятичный тип (Boost имеет один) или работайте в целых числах и склейте в десятичном разделителе самостоятельно. Но в вашем случае, учитывая, что вы просто выводите число без сложных вычислений, округление до 15-го значимого числа даст желаемый эффект: введите

std::setprecision(15)

в выходной поток.

2
По вопросам рекламы [email protected]