I want to replace the calls to boost::lexical_cast<std::string>(d)
with a solution that:
- Does not use locales (I suspect it to be the cause of slow-down in multi-threaded apps),
- Preserves the same output as
lexical_cast
.
I am using a generator written in Boost.Spirit.Karma (because it is faster). But after the change the results are different, because Karma has its own way of displaying fractional parts of double
s.
I know that to some extent one can control the double
generator with policies, but my attempts fail. The best I can come up with is this generator customization and this test program:
#include <limits>
#include <string>
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/spirit/include/karma.hpp>
namespace karma = boost::spirit::karma;
template <typename Num>
struct fp_policy : karma::real_policies<Num>
{
template <typename OutputIterator>
static bool dot (OutputIterator& sink, Num n, unsigned /*precision*/)
{
if (n)
return karma::char_inserter<>::call(sink, '.'); // generate the dot by default
else
return false;
}
static unsigned precision(Num)
{
return 15;
}
};
karma::real_generator<double, fp_policy<double>> const fp_generator {};
std::string karma_to_string(double const& v)
{
std::string ans;
std::back_insert_iterator<std::string> sink {ans};
(void)karma::generate(sink, fp_generator, v);
return ans;
}
void test_number (double x)
{
std::cout << "stream: " << x << "\n";
std::cout << "lexiical_cast: " << boost::lexical_cast<std::string>(x) << "\n";
std::cout << "spirit: " << karma_to_string(x) << "\n";
std::cout << "--------------------------------------------" << std::endl;
}
int main()
{
test_number(0.45359237);
test_number(111.11);
test_number(1.0);
test_number(3.25);
}
And it gives the following output:
stream: 0.453592
lexiical_cast: 0.45359237000000002
spirit: 0.45359237
--------------------------------------------
stream: 111.11
lexiical_cast: 111.11
spirit: 111.109999999999999
--------------------------------------------
stream: 1
lexiical_cast: 1
spirit: 1
--------------------------------------------
stream: 3.25
lexiical_cast: 3.25
spirit: 3.25
--------------------------------------------
And as you can see there are obvious differences. If I go with the default generator for doubles (karma::double_
), results still vary but in different places:
stream: 0.453592
lexiical_cast: 0.45359237000000002
spirit: 0.454
--------------------------------------------
stream: 111.11
lexiical_cast: 111.11
spirit: 111.11
--------------------------------------------
stream: 1
lexiical_cast: 1
spirit: 1.0
--------------------------------------------
stream: 3.25
lexiical_cast: 3.25
spirit: 3.25
--------------------------------------------
My question: how to configure the generator for double
s (or if it is even possible?) so that the output is closer to stream based converters?