102
votes

How do you convert a float to a string in C++ while specifying the precision & number of decimal digits?

For example: 3.14159265359 -> "3.14"

6
why not creating a temp float with the specified precision you want and then convert it to string? - Gilad
@Gilad The 'temp float' doesn't have a 'specified precision' and there are cases when such an approach will break down. This question is basically like asking "what is the equivalent of the '%.2f' format"? - user2864740

6 Answers

147
votes

A typical way would be to use stringstream:

#include <iomanip>
#include <sstream>

double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();

See fixed

Use fixed floating-point notation

Sets the floatfield format flag for the str stream to fixed.

When floatfield is set to fixed, floating-point values are written using fixed-point notation: the value is represented with exactly as many digits in the decimal part as specified by the precision field (precision) and with no exponent part.

and setprecision.


For conversions of technical purpose, like storing data in XML or JSON file, C++17 defines to_chars family of functions.

Assuming a compliant compiler (which we lack at the time of writing), something like this can be considered:

#include <array>
#include <charconv>

double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
                               std::chars_format::fixed, 2);
if (ec == std::errc{}) {
    std::string s(buffer.data(), ptr);
    // ....
}
else {
    // error handling
}
34
votes

The customary method for doing this sort of thing is to "print to string". In C++ that means using std::stringstream something like:

std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();
17
votes

You can use C++20 std::format:

#include <format>

int main() {
  std::string s = std::format("{:.2f}", 3.14159265359); // s == "3.14"
}

or the fmt::format function from the {fmt} library, std::format is based on (godbolt):

#include <fmt/core.h>

int main() {
  std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}

where 2 is a precision.

It is not only shorter than using iostreams or sprintf but also significantly faster and is not affected by the locale.

15
votes

Another option is snprintf:

double pi = 3.1415926;

std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);

Demo. Error handling should be added, i.e. checking for written < 0.

12
votes

Here a solution using only std. However, note that this only rounds down.

    float number = 3.14159;
    std::string num_text = std::to_string(number);
    std::string rounded = num_text.substr(0, num_text.find(".")+3);

For rounded it yields:

3.14

The code converts the whole float to string, but cuts all characters 2 chars after the "."

5
votes

Here I am providing a negative example where your want to avoid when converting floating number to strings.

float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;

You get

99463 99.463 99.462997

Note: the num variable can be any value close to 99.463, you will get the same print out. The point is to avoid the convenient c++11 "to_string" function. It took me a while to get out this trap. The best way is the stringstream and sprintf methods (C language). C++11 or newer should provided a second parameter as the number of digits after the floating point to show. Right now the default is 6. I am positing this so that others won't wast time on this subject.

I wrote my first version, please let me know if you find any bug that needs to be fixed. You can control the exact behavior with the iomanipulator. My function is for showing the number of digits after the decimal point.

string ftos(float f, int nd) {
   ostringstream ostr;
   int tens = stoi("1" + string(nd, '0'));
   ostr << round(f*tens)/tens;
   return ostr.str();
}