I have an issue regarding conversion from float to c++ string using ostringstream. Here is my line:
void doSomething(float t)
{
ostringstream stream;
stream << t;
cout << stream.str();
}
when t has value -0.89999 it is round off to -0.9, but when it's value is 0.0999 or lesser than this say 1.754e-7, it just prints without round off. what can be the solution for this.
You need to set the precision for ostringstream using precision
e.g
stream.precision(3);
stream<<fixed; // for fixed point notation
//cout.precision(3); // display only
stream << t;
cout<<stream.str();
If you want a particular number of significant figures displayed try using setprecision(n) where n is the number of significant figures you want.
#include <iomanip>
void doSomething(float t)
{
ostringstream stream;
stream << std::setprecision(4) << t;
cout << stream.str();
}
If you want fixed-point instead of scientific notation, use std::fixed:
stream << std::fixed << t;
Additionally you might want to set the precision as mentioned.
Use setprecision:
stream << setprecision(5) <<t ;
Now, your string stream.str() will be of the required precision.
Related
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"
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
}
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();
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.
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.
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 "."
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();
}
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"
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
}
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();
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.
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.
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 "."
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();
}
I need help on keeping the precision of a double. If I assign a literal to a double, the actual value was truncated.
int main() {
double x = 7.40200133400;
std::cout << x << "\n";
}
For the above code snippet, the output was 7.402
Is there a way to prevent this type of truncation? Or is there a way to calculate exactly how many floating points for a double? For example, number_of_decimal(x) would give 11, since the input is unknown at run-time so I can't use setprecision().
I think I should change my question to:
How to convert a double to a string without truncating the floating points. i.e.
#include <iostream>
#include <string>
#include <sstream>
template<typename T>
std::string type_to_string( T data ) {
std::ostringstream o;
o << data;
return o.str();
}
int main() {
double x = 7.40200;
std::cout << type_to_string( x ) << "\n";
}
The expected output should be 7.40200 but the actual result was 7.402. So how can I work around this problem? Any idea?
Due to the fact the float and double are internally stored in binary, the literal 7.40200133400 actually stands for the number 7.40200133400000037653398976544849574565887451171875
...so how much precision do you really want? :-)
#include <iomanip>
int main()
{
double x = 7.40200133400;
std::cout << std::setprecision(51) << x << "\n";
}
And yes, this program really prints 7.40200133400000037653398976544849574565887451171875!
You must use setiosflags(ios::fixed) and setprecision(x).
For example, cout << setiosflags(ios::fixed) << setprecision(4) << myNumber << endl;
Also, don't forget to #include <iomanip.h>.
std::cout << std::setprecision(8) << x;
Note that setprecision is persistent and all next floats you print will be printed with that precision, until you change it to a different value. If that's a problem and you want to work around that, you can use a proxy stringstream object:
std::stringstream s;
s << std::setprecision(8) << x;
std::cout << s.str();
For more info on iostream formatting, check out the Input/output manipulators section in cppreference.
Solution using Boost.Format:
#include <boost/format.hpp>
#include <iostream>
int main() {
double x = 7.40200133400;
std::cout << boost::format("%1$.16f") % x << "\n";
}
This outputs 7.4020013340000004.
Hope this helps!
The only answer to this that I've come up with is that there is no way to do this (as in calculate the decimal places) correctly! THE primary reason for this being that the representation of a number may not be what you expect, for example, 128.82, seems innocuous enough, however it's actual representation is 128.8199999999... how do you calculate the number of decimal places there??
Responding to your answer-edit: There is no way to do that. As soon as you assign a value to a double, any trailing zeroes are lost (to the compiler/computer, 0.402, 0.4020, and 0.40200 are the SAME NUMBER). The only way to retain trailing zeroes as you indicated is to store the values as strings (or do trickery where you keep track of the number of digits you care about and format it to exactly that length).
Let s make an analogous request: after initialising an integer with 001, you would want to print it with the leading zeroes. That formatting info was simply never stored.
For further understanding the double precision floating point storage, look at the IEEE 754 standard.
Doubles don't have decimal places. They have binary places. And binary places and decimal places are incommensurable (because log2(10) isn't an integer).
What you are asking for doesn't exist.
The second part of the question, about how to preserve trailing zeroes in a floating point value from value specification to output result, has no solution. A floating point value doesn't retain the original value specification. It seems this nonsensical part was added by an SO moderator.
Regarding the first and original part of the question, which I interpret as how to present all significant digits of 7.40200133400, i.e. with output like 7.402001334, you can just remove trailing zeroes from an output result that includes only trustworthy digits in the double value:
#include <assert.h> // assert
#include <limits> // std::(numeric_limits)
#include <string> // std::(string)
#include <sstream> // std::(ostringstream)
namespace my{
// Visual C++2017 doesn't support comma-separated list for `using`:
using std::fixed; using std::numeric_limits; using std::string;
using std::ostringstream;
auto max_fractional_digits_for_positive( double value )
-> int
{
int result = numeric_limits<double>::digits10 - 1;
while( value < 1 ) { ++result; value *= 10; }
return result;
}
auto string_from_positive( double const value )
-> string
{
ostringstream stream;
stream << fixed;
stream.precision( max_fractional_digits_for_positive( value ) );
stream << value;
string result = stream.str();
while( result.back() == '0' )
{
result.resize( result.size() - 1 );
}
return result;
}
auto string_from( double const value )
-> string
{
return (0?""
: value == 0? "0"
: value < 0? "-" + string_from_positive( -value )
: string_from_positive( value )
);
}
}
#include<iostream>
auto main()
-> int
{
using std::cout;
cout << my::string_from( 7.40200133400 ) << "\n";
cout << my::string_from( 0.00000000000740200133400 ) << "\n";
cout << my::string_from( 128.82 ) << "\n";
}
Output:
7.402001334
0.000000000007402001334
128.81999999999999
You might consider adding logic for rounding to avoid long sequences of 9's, like in the last result.
double val = 0.1;
std::stringstream ss;
ss << val;
std::string strVal= ss.str();
In the Visual Studio debugger, val has the value 0.10000000000000001 (because 0.1 can't be represented).
When val is converted using stringstream, strVal is equal to "0.1". However, when using boost::lexical_cast, the resulting strVal is "0.10000000000000001".
Another example is the following:
double val = 12.12305000012;
Under visual studio val appears as 12.123050000119999, and using stringstream and default precision (6) it becomes 12.1231. I don't really understand why it is not 12.12305(...).
Is there a default precision, or does stringstream have a particular algorithm to convert a double value which can't be exactly represented?
Thanks.
You can change the floating-point precision of a stringstream as follows:
double num = 2.25149;
std::stringstream ss(stringstream::in | stringstream::out);
ss << std::setprecision(5) << num << endl;
ss << std::setprecision(4) << num << endl;
Output:
2.2515
2.251
Note how the numbers are also rounded when appropriate.
For anyone who gets "error: ‘setprecision’ is not a member of ‘std’" you must #include <iomanip> else setprecision(17) will not work!
There are two issues you have to consider. The first is the precision
parameter, which defaults to 6 (but which you can set to whatever you
like). The second is what this parameter means, and that depends on the
format option you are using: if you are using fixed or scientific
format, then it means the number of digits after the decimal (which in
turn has a different effect on what is usually meant by precision in the
two formats); if you are using the default precision, however (ss.setf(
std::ios_base::fmtflags(), std::ios_base::formatfield ), it means the
number of digits in the output, regardless of whether the output was
actually formatted using scientific or fixed notation. This explains
why your display is 12.1231, for example; you're using both the
default precision and the default formattting.
You might want to try the following with different values (and maybe
different precisions):
std::cout.setf( std::ios_base::fmtflags(), std::ios_base::floatfield );
std::cout << "default: " << value[i] << std::endl;
std::cout.setf( std::ios_base::fixed, std::ios_base::floatfield );
std::cout << "fixed: " << value[i] << std::endl;
std::cout.setf( std::ios_base::scientific, std::ios_base::floatfield );
std::cout << "scientific: " << value[i] << std::endl;
Seeing the actual output will probably be clearer than any detailed description:
default: 0.1
fixed: 0.100000
scientific: 1.000000e-01
The problem occurs at the stream insertion ss << 0.1; rather than at the conversion to string. If you want non-default precision you need to specify this prior to inserting the double:
ss << std::setprecision(17) << val;
On my computer, if I just use setprecision(16) I still get "0.1" rather than "0.10000000000000001". I need a (slightly bogus) precision of 17 to see that final 1.
Addendum
A better demonstration arises with a value of 1.0/3.0. With the default precision you get a string representation of "0.333333". This is not the string equivalent of a double precision 1/3. Using setprecision(16) makes the string "0.3333333333333333"; a precision of 17 yields "0.33333333333333331".
I need help on keeping the precision of a double. If I assign a literal to a double, the actual value was truncated.
int main() {
double x = 7.40200133400;
std::cout << x << "\n";
}
For the above code snippet, the output was 7.402
Is there a way to prevent this type of truncation? Or is there a way to calculate exactly how many floating points for a double? For example, number_of_decimal(x) would give 11, since the input is unknown at run-time so I can't use setprecision().
I think I should change my question to:
How to convert a double to a string without truncating the floating points. i.e.
#include <iostream>
#include <string>
#include <sstream>
template<typename T>
std::string type_to_string( T data ) {
std::ostringstream o;
o << data;
return o.str();
}
int main() {
double x = 7.40200;
std::cout << type_to_string( x ) << "\n";
}
The expected output should be 7.40200 but the actual result was 7.402. So how can I work around this problem? Any idea?
Due to the fact the float and double are internally stored in binary, the literal 7.40200133400 actually stands for the number 7.40200133400000037653398976544849574565887451171875
...so how much precision do you really want? :-)
#include <iomanip>
int main()
{
double x = 7.40200133400;
std::cout << std::setprecision(51) << x << "\n";
}
And yes, this program really prints 7.40200133400000037653398976544849574565887451171875!
You must use setiosflags(ios::fixed) and setprecision(x).
For example, cout << setiosflags(ios::fixed) << setprecision(4) << myNumber << endl;
Also, don't forget to #include <iomanip.h>.
std::cout << std::setprecision(8) << x;
Note that setprecision is persistent and all next floats you print will be printed with that precision, until you change it to a different value. If that's a problem and you want to work around that, you can use a proxy stringstream object:
std::stringstream s;
s << std::setprecision(8) << x;
std::cout << s.str();
For more info on iostream formatting, check out the Input/output manipulators section in cppreference.
Solution using Boost.Format:
#include <boost/format.hpp>
#include <iostream>
int main() {
double x = 7.40200133400;
std::cout << boost::format("%1$.16f") % x << "\n";
}
This outputs 7.4020013340000004.
Hope this helps!
The only answer to this that I've come up with is that there is no way to do this (as in calculate the decimal places) correctly! THE primary reason for this being that the representation of a number may not be what you expect, for example, 128.82, seems innocuous enough, however it's actual representation is 128.8199999999... how do you calculate the number of decimal places there??
Responding to your answer-edit: There is no way to do that. As soon as you assign a value to a double, any trailing zeroes are lost (to the compiler/computer, 0.402, 0.4020, and 0.40200 are the SAME NUMBER). The only way to retain trailing zeroes as you indicated is to store the values as strings (or do trickery where you keep track of the number of digits you care about and format it to exactly that length).
Let s make an analogous request: after initialising an integer with 001, you would want to print it with the leading zeroes. That formatting info was simply never stored.
For further understanding the double precision floating point storage, look at the IEEE 754 standard.
Doubles don't have decimal places. They have binary places. And binary places and decimal places are incommensurable (because log2(10) isn't an integer).
What you are asking for doesn't exist.
The second part of the question, about how to preserve trailing zeroes in a floating point value from value specification to output result, has no solution. A floating point value doesn't retain the original value specification. It seems this nonsensical part was added by an SO moderator.
Regarding the first and original part of the question, which I interpret as how to present all significant digits of 7.40200133400, i.e. with output like 7.402001334, you can just remove trailing zeroes from an output result that includes only trustworthy digits in the double value:
#include <assert.h> // assert
#include <limits> // std::(numeric_limits)
#include <string> // std::(string)
#include <sstream> // std::(ostringstream)
namespace my{
// Visual C++2017 doesn't support comma-separated list for `using`:
using std::fixed; using std::numeric_limits; using std::string;
using std::ostringstream;
auto max_fractional_digits_for_positive( double value )
-> int
{
int result = numeric_limits<double>::digits10 - 1;
while( value < 1 ) { ++result; value *= 10; }
return result;
}
auto string_from_positive( double const value )
-> string
{
ostringstream stream;
stream << fixed;
stream.precision( max_fractional_digits_for_positive( value ) );
stream << value;
string result = stream.str();
while( result.back() == '0' )
{
result.resize( result.size() - 1 );
}
return result;
}
auto string_from( double const value )
-> string
{
return (0?""
: value == 0? "0"
: value < 0? "-" + string_from_positive( -value )
: string_from_positive( value )
);
}
}
#include<iostream>
auto main()
-> int
{
using std::cout;
cout << my::string_from( 7.40200133400 ) << "\n";
cout << my::string_from( 0.00000000000740200133400 ) << "\n";
cout << my::string_from( 128.82 ) << "\n";
}
Output:
7.402001334
0.000000000007402001334
128.81999999999999
You might consider adding logic for rounding to avoid long sequences of 9's, like in the last result.