Reputation: 237
i have the following problem:
customer want to present double
type to a string
by an optimal way. it need to be converted to string and showed on a form(sms, table and other).
100000000.949999 needs to be converted in 100000000.950;
10.000000001 -> 10.0;
100000000000000.19292 -> 1e+14;
1000.123456789 -> 1000.123;
0.00001 -> 0.0;
The code for converting is a performance critical, it means that no std::stringstream
+ setprecision()
should be used.
It will be great to implement params 'precision' as argument of my toStringNew()
function, but this improvements may critically affects all our system, and we are planning implement it in the next release.
But this problem is actual now.
I wrote the following code:
inline bool toStringNew(std::string& str, double const& value)
{
static const char *zero_double_str = "0.0";
static const double zero_double_limit = 0.001;
static const int max_double_prec_symbol = 13;
static const int max_fract_num = 3;
static const int max_fract_mul = pow(10, max_fract_num);
str.clear();
//get digits of integer part
double fabs_value = fabs(value);
int64_t len = log10(fabs_value);
//Round 2 zero
if(len <= 0) //it means that only fraction part is present
{
if(fabs_value < zero_double_limit)
{
str = zero_double_str;
return true;
}
//use default
return boost::spirit::karma::generate(std::back_inserter(str), value);
}
else if(len > max_double_prec_symbol) //default
{
return boost::spirit::karma::generate(std::back_inserter(str), value);
}
//cast to integer
int64_t i = static_cast<int64_t>(value);
//cast fract to integer
int64_t fract_i = static_cast<int64_t>(round((value - i)* max_fract_mul));
//reserve string memory
size_t str_len = len + 1 + max_fract_num + (value > 0 ? 0 : 1) + 1;
str.reserve(str_len);
//convert integer
boost::spirit::karma::generate(std::back_inserter(str), i);
str+='.';
//convert fract
if(fract_i > 0)
{
str+='.';
int64_t fract_i_len = log10(fract_i);
//fill zero before: 0.001 -> 1 -> 001
while(++fract_i_len < max_fract_num)
{
str += '0';
}
//remove zero after: 010 -> 01
while(!(fract_i % 10))
{
fract_i = fract_i / 10;
}
boost::spirit::karma::generate(std::back_inserter(str), fract_i);
}
boost::spirit::karma::generate(std::back_inserter(str), fract_i);
return true;
}
This works at 1,5 times faster than boost::spirit::karma::generate()
for double
type.
Can you give me some advices how to satisfy my customer?
Upvotes: 12
Views: 426
Reputation: 1552
I would look at the C++ String Toolkit Library. I have used it for parsing and number conversion and it has shown to be very fast.
#include <cmath>
#include <strtk.hpp>
#include <iostream>
using namespace std;
int main ( int argc, char **argv )
{
double pi = M_PI;
std::cout << strtk::type_to_string<double>( pi ) << std::endl;
return 0;
}
Upvotes: 6
Reputation: 70929
If performance is critical maybe use snprintf. It will be better than your home grown solution and also I think it will perform better. Using the *
format specifier you can also make the precision an argument.
Upvotes: 0