0

I want to convert a double value into a std::string. Currently I'm writing

return std::to_string(double_value);

But this only returns 7 digits because internally to_string() just uses std::vsnprintf with a %f format specifier (see also here).

I could now just call std::vsnprintf manually with %.15f as format specifier but this leads to trailing zeros.

My (in my eyes very obvious) goal now is to have an approach like this:

string o1 = to_string(3.14)
string o2 = to_string(3.1415926536)
assert(o1 == "3.14")
assert(o2 == "3.1415926536")

Here is a nice elaboration on trimming trailing zeros from the %.20 output but this answer is about 8 years old.

Maybe things have changed? Can I convert a double with double precision without trailing zeros in C++ today?

Solution:

Based on 2mans answer you can write a generic function like this:

template<typename T>
inline std::string tostr(T value) {
    std::ostringstream s;
    s.precision(std::numeric_limits<T>::digits10);
    s << value;
    return s.str();
}

which will behaves like desired for numeric types. Note that I took digits10 rather than max_digits10 to favor a nice decimal representation rather than more digits and trailing ..0000001

Also IMHO it's worth to add that [v][s][n]printf() together with the format string "%.15g" (rather than 'f') will also trim trailing zeros (won't work with more digits because they could not be represented with 64bit which would lead to things like a trailing '1', e.g. 3.12 -> "3.1200000000000001")

Still strange:

Maybe someone can tell me why std::to_string(double) which was introduced with C++-11 hard-codes to vsnprintf(..., "%f", ...) rather than so something like vsnprintf("%.15g") which would result in a more precise representation without affecting C code?

Community
  • 1
  • 1
frans
  • 8,868
  • 11
  • 58
  • 132
  • One nice thing about C is that it's *extremely* backwards compatible. That the C code in the linked answer is eight years old doesn't matter, it will still work, and nothing relevant has changed with the C11 standard. It should not be to hard to translate to C++ either. Without something like that it's impossible though, unless you actually know the number of significant digits beforehand. – Some programmer dude Mar 01 '16 at 13:47
  • 1
    It doesn't matter if it's eight years old or eight hours old: good code is good code. (Plus, it's C++...It doesn't change much). – Ellis Mar 01 '16 at 13:49
  • 1
    How do you plan to handle floating point round off? I attempted something simple adding characters to a string but `3.14` may not be exactly `3.14` when stored in memory. Without limiting the digits it is possible to get `2.12000000005` when you want `2.12`. – Matt Mar 01 '16 at 14:34

1 Answers1

3

You can use string stream (sstring) with stream manipulators, see example below:

  std::stringstream ss1;
  std::stringstream ss2;
  ss1.precision(15);    
  ss1 << 3.14;
  std::cout << ss1.str()<<' '<<("3.14" == ss1.str())<<std::endl;
  ss2.precision(15);
  ss2 << 3.1415926536;
  std::cout << ss2.str()<<' '<<("3.1415926536" == ss2.str())<<std::endl;

Or you can use boost format. Here's a link!

  std::cout<<format("%.2f") % 3.14 <<std::endl;
  std::cout<<format("%.10f") % 3.1415926536 <<std::endl;
2man
  • 98
  • 7
  • In this example you still have to manually specify the precision. With `vsnprintf()` it's correctly trimmed if you don't add a precision to `%f` but it's limited to 7 digits. – frans Mar 01 '16 at 14:09
  • You can set precision to 15. When you cast stream to string, string will no contains "0" at end. – 2man Mar 01 '16 at 14:33
  • you're right - and you must not use the maximum number of decimal digits which can be represented by a `double` (which would be 17). (see my edit) – frans Mar 01 '16 at 16:02