130

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"

3
  • why not creating a temp float with the specified precision you want and then convert it to string? Commented Mar 22, 2015 at 22:32
  • @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"? Commented Mar 22, 2015 at 22:33
  • 1
    See stackoverflow.com/questions/14432043/c-float-formatting if this is just need for IO. Commented Mar 22, 2015 at 22:36

8 Answers 8

193

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
}
Sign up to request clarification or add additional context in comments.

Comments

56

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.

Disclaimer: I'm the author of {fmt} and C++20 std::format.

3 Comments

If I try std::format("{:.2f}", 3 / 2) it won't compile with call to immediate function is not a constant expression. Why?
3 / 2 is an integer and .2f is an invalid format specifier for an integer. You probably want to use floating point instead.
Nice work! Goodbye std::setprecision(), I'm moving to C++20.
36

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();

Comments

24

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 "."

3 Comments

Only thing is that this way you are not actually rounding the number.
@ChrCury78 as stated in my answer this only rounds down. If you want a normal rounding simply add 5 to the diget following your value. For example number + 0.005 in my case.
@Sebastian R. why not add the comment " If you want a normal rounding simply add 5 to the diget following your value. For example number + 0.005 in my case" to your answer? you have my thumbs up but you could have worded your answer to include how to round it since you obviously know.
19

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.

10 Comments

Why would snprintf be better in this case? Please explain... It certainly won't be faster, produce less code [I have written a printf implementation, it's fairly compact at just under 2000 lines of code, but with macro expansions gets to around 2500 lines]
@MatsPetersson I strongly believe that it will be faster. That's the reason I made this answer in the first place.
@MatsPetersson I have performed measurements (GCC 4.8.1, -O2) that indicate that snprintf is indeed taking less time, by factor 17/22. I will upload the code shortly.
@MatsPetersson My benchmark is probably flawed, but the stringstream version takes twice as long as the snprintf version at 1000000 iterations (Clang 3.7.0, libstdc++, -O2).
Remember it is safe to write directly to buffer owned by std::string only starting with C++11 standard.
|
4

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();
}

Comments

3

You can use fmt library.

3.14159265359 -> "3.14"

#include <fmt/format.h>
#include <string>

double pi = 3.14159265359;
std::string st = fmt::format("pi = {:.2f}", pi);

2 Comments

there are some answers that rely on standard libraries. So it is better to provide some context about the library you are suggesting and why it is preferable to the standard libraries
Fair enough. The advantage of fmt is that it provides great flexibility of the C-like printf family functions while retaining the type-safe of std::cout while getting a huge speed boost compared to the latter. I'd like to refer reader to the documentation of fmt to learn more about it. For those who have access to C++20 library, you can use std::print which uses fmt as the reference implementation.
1

Using nothing but std:

float number = 3.14159265359;
int precision = 2;
std::string rounded = std::to_string(
  std::round(number * std::pow(10, precision)) /
  std::pow(10, precision)).substr(
    0, std::to_string(
      std::round(number * std::pow(10, precision)) /
      std::pow(10, precision)).find(".") + precision + 1);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.