I am using stringstream to parse float from string.
std::stringstream strs(cp.val);
strs.precision(5);
strs<<std::setprecision(5);
float x; strs>>x;
however the set precision functions do not seem to work..
is there any way to force precision in parsing not printing ?
The precision (along with things like fixed and scientific) only affect output; input will parse anything that looks like a numeric value, extracting all of the characters which could possibly be part of any numeric value. (This includes hex characters, and the 'X' which might occur for integral input.) If you want to limit the format in any way, you'll have to read it as a string, validate the format, and then use std::istringstream to convert it.
stringstram does not allow precision on parsing, but you may set the double precision after parsing.
E.g.
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cmath>
using namespace std; //do not use that in real project.
int main()
{
// Initial declarations
stringstream ss("13.321646");
double x = 0.0;
// Parse the double
ss >> x;
// Set the double precision to 2decimals
double roundedX = round(x*100)/100;
// output solution
cout << x << endl;
cout << setprecision(5) << x << endl;
cout << roundedX << endl;
return 0;
}
Obvious note: That allow to reduce precision, not to improve it.
Related
Updated:
I have been trying all methods I could find in stackoverflow, and still could not find a solution.
My point is, I have a string "23.46" and would like to transfer it to double or float anyway. This is in order to be used in another library.
But no matter how I trancate,floor,*100,add,round, it always gives me 24.4600000001 or something like this.
I know there are some precision issue while transfer. But I do need a way to give me a number that double d = 24.46 precisely.
==============================================================================
I have many string values and some of them are double with converted precision as below:
char pt[100];
sprintf(pt, "%.2lf", i);
return string(pt);
Now on the other side of the code, I need to convert the strings back to double, but I tried strtod and atof with precision loss.
My questions are:
what is the good way to check if a string could be a double?
how to convert string back to double with given precision? I only need it to %.2lf be like:
0.21, 35.45, ...
Thanks so much!
Given that you say that using std::strtod is not giving you a solution to the problem, you can use stringstreams to parse strings as doubles, you can also use its flags to assert if the contents of the string are convertible.
Here is an example with some conversions back and forth, and with checks to see if the whole string (not just some digits in it), is parseable as double:
Live demo
#include <iostream>
#include <sstream>
#include <iomanip>
int main()
{
std::string str = "23.4k7"; //string with a character in the middle
std::istringstream ss(str); //put string in a stream
double num;
ss >> num; //convert string to double
if(!ss.fail() && ss.eof()) { //check if the whole string is parseable
std::cout << "is parseable" << std::endl;
}
else {
std::cout << "is not parseable";
return EXIT_FAILURE;
}
std::stringstream to_num;
to_num << std::fixed << std::setprecision(2) << num; //double to string 2 decimal places
std::cout << to_num.str();
to_num >> num; //final conversion to double
}
Since the string has an alphabetic character in it, this will output:
is not parseable
But if you use a valid number it will output the converted value:
string str:
234.2345
Output:
is parseable
234.23
Note that you could use
Live demo
if(ss >> num)
std::cout << "is parseable";
This, however, has a weakness, it will still parse if you have for instance 123.45rt56, 123.45 will be parsed, the rest will be discarded, the way it is in the sample code, if the string has any character, it will return an error. You can choose the more appropriate way for your needs.
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.
I have this case where a double is converted to a string using a stringstream. Now, I have to get back that value somewhere else (no, I have no access to the original double), so I have to parse the formatted string.
Ofcourse, I can read it just with a stringstream as well, but is that safe? Will it always work, for all values?
std::ostringstream doubleToString;
double myDouble = 3.14;
doubleToString << myDouble;
std::string convertedDouble = doubleToString.str();
std::istringstream stringToDouble(convertedDouble);
double newDouble;
stringToDouble >> newDouble;
In the example above, will myDouble always be equal to newDouble?
Note: marginal differences (0.00000000001) are not my concern.
No, it will not always work. You can prove this to yourself using this minor modification of your code:
#include <sstream>
#include <iostream>
#include <string>
#include <cassert>
int main()
{
std::ostringstream doubleToString;
double zero = 0;
double myDouble = 3.14/zero;
doubleToString << myDouble;
std::string convertedDouble = doubleToString.str();
std::cout << "convertedDouble = " << convertedDouble << std::endl;
std::istringstream stringToDouble(convertedDouble);
double newDouble;
stringToDouble >> newDouble;
std::cout << "newDouble = " << newDouble << std::endl;
assert(newDouble == myDouble);
}
When I run this code on my machine, I get this output:
convertedDouble = inf
newDouble = 0
xlat: xlat.cpp:19: int main(): Assertion `newDouble == myDouble' failed.
Aborted (core dumped)
Update:
Note that if you always start with a double in the range of representable floating point numbers on your particular machine (that is std::numeric_limits<double>::min() <= x <= std::numeric_limits<double>::max()) it still isn't guaranteed. As an example of this try the code above with double myDouble = 1/3.0;. The issue is one of precision when emitting the double to a string. We can try to address that by modifying the code to use this:
doubleToString <<
std::setprecision(std::numeric_limits<double>::digits10) << myDouble;
This has the effect of setting the precision to as many decimal digits as are needed for an integer value that will always survive transformation into and back from a double. However, it still won't work for all double values!
double myDouble = pow(1/3.0, 300);
This value will cause the assert to trigger. The reason is that the digits10 is only for the mantissa portion of the floating point number and doesn't represent the exponent. Getting completely pedantic here, we can set the right value as:
constexpr int dblprecision = std::numeric_limits<double>::digits10
+ ceil(log10(std::numeric_limits<double>::max_exponent10));
doubleToString << std::setprecision(dblprecision) << myDouble;
Note that this is only needed in the double-to-string conversion direction and not the other way.
So with the understanding that the input value must be in the indicated range, and provided you set the precision for the conversion to string, I think this will always result in the original double, assuming no bugs in the implementation of the compiler or library.
I have a float number and I want to print one digit after decimal. How can I do this using cout? I have tried the following code but its giving wrong display.
#include <iostream>
using namespace std;
int main()
{
float time = 2.2;
cout.precision(1);
cout << time << endl;
return 0;
}
You need to set tge precision to one and float formatting flags to fixed:
std::cout << std::fixed << std::setprecision(1);
BTW, don't use std::endl. To get a newline use '\n' and if you really mean to flush the stream use std::flush.
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.