I have a small problem with stringstream. It loses precision when I use it to convert string to double.
const std::string str = "44.23331002";
double x;
stringstream ss;
ss << str;
ss >> x;
cout << str << " = " << x << endl;
The output is:
44.23331002 = 44.2333
Why is this? Does it convert to float and has limited digit precision?
You need to set the precision on the output stream:
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;
int main() {
const std::string str = "44.23331002";
double x;
stringstream ss;
ss << str;
ss >> x;
cout << str << " = " << std::setprecision(10) << x << endl;
}
Output:
44.23331002 = 44.23331002
(Demo)
calcto answered correctly.and You can change precision in two way:
std::setprecision(10) and std::cout.precision(10)
Related
I have problem, but I don't know how fix it. Could someone help me?
Problem. In text file
1. 20.20
2. 3
I want to take data from file, and use it. My code:
int main()
{
string tp;
float data_1 = 0, data_2 = 0, total = 0;
std::fstream file;
file.open("text.txt", ios::in);
std::getline(file, tp);
data_1 = std::stof(tp);
std::getline(file, tp);
data_2 = std::stof(tp);
total = dat_1 * data_2;
cout << "Total: " << total << endl;
}
In the program total is not 60.60, but it need be. Where is problem?
#include <iostream>
#include <string>
#include <fstream>
int main(void)
{
std::string tp;
float data_1 = 0, data_2 = 0, total = 0;
std::ifstream file("text.txt");
std::getline(file, tp);
data_1 = std::stof(tp);
std::getline(file, tp);
data_2 = std::stof(tp);
total = data_1 * data_2; // you wrote dat_1 instead of data_1
std::cout << total << std::endl;
return (0);
}
Firstly, dat_1 is not declared and it should be data_1.
Then, you can use std::fixed to have it let specify the number of digits after dot and std::setprecision to specify the number of digits.
cout << "Total: " << std::fixed << std::setprecision(2) << total << endl;
References:
std::fixed, std::scientific, std::hexfloat, std::defaultfloat - cppreference.com
std::setprecision - cppreference.com
If you really want 60,60, not 60.60, printed, you can use std::replace to change the character.
#include <iostream>
#include <string>
#include <iomanip>
#include <algorithm>
#include <sstream>
using std::ios;
using std::cout;
using std::endl;
int main(){
float total = 60.60;
std::stringstream ss;
ss << std::fixed << std::setprecision(2) << total << endl;
std::string str = ss.str();
std::replace(str.begin(), str.end(), '.', ',');
cout << "Total: " << str << endl;
}
I have been looking into a problem whereby I am converting a float to a human readable format, and back. Namely a string. I have ran into issues using stringstream and found that atof produces "better" results.
Notice, I do not print out the data in this case, I used the debugger to retrieve the values:
const char *val = "73.31";
std::stringstream ss;
ss << val << '\0';
float floatVal = 0.0f;
ss >> floatVal; //VALUE IS 73.3100052
floatVal = atof(val); //VALUE IS 73.3099976
There is probably a reasonable explanation to this. If anybody can enlighten me I'd be greatful :).
Answer is based on the assumption that OP uses MSVC
atof is indeed better in reading floating point values than istream.
See this example:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
int main()
{
const char *val = "73.31";
std::stringstream ss;
ss << val;
float floatVal = 0.0f;
ss >> floatVal;
std::cout << "istream>>(float&) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
double doubleVal = atof(val);
std::cout << "double atof(const char*) :" << std::setw(18) << std::setprecision(15) << doubleVal << std::endl;
floatVal = doubleVal;
std::cout << "(float)double atof(const char*) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
doubleVal = floatVal;
std::cout << "(double)(float)double atof(const char*) :" << std::setw(18) << std::setprecision(15) << floatVal << std::endl;
}
Output:
istream>>(float&) : 73.3100051879883
double atof(const char*) : 73.31
(float)double atof(const char*) : 73.3099975585938
(double)(float)double atof(const char*) : 73.3099975585938
The compiler even warns about the conversion from doubleto float this:
warning C4244: '=': conversion from 'double' to 'float', possible loss of data
I also found this page: Conversions from Floating-Point Types
Update:
The value 73.3099975585938 seems to be the correct float interpretation of the double value 73.31.
Update:
istream>>(double&) works correctly as well:
#include <iostream>
#include <sstream>
#include <iomanip>
#include <cstdlib>
int main()
{
const char *val = "73.31";
std::stringstream ss;
ss << val;
double doubleVal = 0.0f;
ss >> doubleVal;
std::cout << "istream>>(double&) :" << std::setw(18) << std::setprecision(15) << doubleVal << std::endl;
}
Output:
istream>>(double&) : 73.31
For arithmetic types istream::operator>> uses num_get::get.
num_get::get should be using something like scanf("%g") for float source
BUT:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <iomanip>
#include <cstdlib>
int main()
{
std::string s = "73.31";
float f = 0.f;
sscanf(s.c_str(), "%g", &f);
std::cout << std::setw(18) << std::setprecision(15) << f << std::endl;
}
Output:
73.3099975585938
For me this looks like there might be a bug in Microsoft num_get
I am trying to solve the relatively simple problem of being able to write a double to a file and then to read the file into a double again. Based on this answer I decided to use the human readable format.
I have successfully circumvented the problems some compilers have with nan and [-]infinity according to this question. With finite numbers I use the std::stod function to convert the string representation of a number into the number itself. But from time to time the parsing fails with numbers close to zero, such as in the following example:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
stream << small;
std::cout << "serialized: " << stream.str() << std::endl;
double out = std::stod(stream.str());
std::cout << "de-serialized: " << out << std::endl;
return 0;
}
On my machine the result is:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
terminate called after throwing an instance of 'std::out_of_range'
what(): stod
The program has unexpectedly finished.
That is, the number is too close to zero to be properly parsed. At first I thougth that the problem is that this number is denormal, but this doesn't seem to be the case, since the mantissa starts with a 9 and not a 0.
Qt on the other hand has no problems with this number:
#include <cmath>
#include <limits>
#include <QString>
#include <QTextStream>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
QString string = QString::number(small, 'g', maxPrecision);
QTextStream stream(stdout);
stream.setRealNumberPrecision(maxPrecision);
stream << "serialized: " << string << '\n';
bool ok;
double out = string.toDouble(&ok);
stream << "de-serialized: " << out << '\n' << (ok?"ok":"not ok") << '\n';
return 0;
}
Outputs:
serialized: 9.2263152681638151025201733115952403273156653201666065e-318
de-serialized: 9.2263152681638151025201733115952403273156653201666065e-318
ok
Summary:
Is this a bug in the gcc implementation of standard library?
Can I circumvent this elegantly?
Should I just use Qt?
Answering question #2:
This is probably my "C-way" kind of thinking, but you could copy the double into a uint64_t (mem-copying, not type-casting), serialize the uint64_t instead, and do the opposite on de-serialization.
Here is an example (without even having to copy from double into uint64_t and vice-versa):
uint64_t* pi = (uint64_t*)&small;
stringstream stream;
stream.precision(maxPrecision);
stream << *pi;
cout << "serialized: " << stream.str() << endl;
uint64_t out = stoull(stream.str());
double* pf = (double*)&out;
cout << "de-serialized: " << *pf << endl;
Please note that in order to avoid breaking strict-aliasing rule, you actually do need to copy it first, because the standard does not impose the allocation of double and uint64_t to the same address-alignment:
uint64_t ismall;
memcpy((void*)&ismall,(void*)&small,sizeof(small));
stringstream stream;
stream.precision(maxPrecision);
stream << ismall;
cout << "serialized: " << stream.str() << endl;
ismall = stoull(stream.str());
double fsmall;
memcpy((void*)&fsmall,(void*)&ismall,sizeof(small));
cout << "de-serialized: " << fsmall << endl;
If you're open to other recording methods you can use frexp:
#include <cmath>
#include <iostream>
#include <sstream>
#include <limits>
const std::size_t maxPrecision = std::numeric_limits<double>::digits;
const double small = std::exp(-730.0);
int main()
{
std::stringstream stream;
stream.precision(maxPrecision);
int exp;
double x = frexp(small, &exp);
//std::cout << x << " * 2 ^ " << exp << std::endl;
stream << x << " * 2 ^ " << exp;
int outexp;
double outx;
stream.seekg(0);
stream >> outx;
stream.ignore(7); // >> " * 2 ^ "
stream >> outexp;
//std::cout << outx << " * 2 ^ " << outexp << std::endl;
std::cout << small << std::endl << outx * pow(2, outexp) << std::endl;
return 0;
}
So... I want to create simple HTTP Chunked transfer encoding prototype. I have messages as std::strings. And my server API is all string based... so I wonder how to turn std::string length into hex and than back into string?
So say we had std::string("This is the data in the first chunk\r\n").length() that would return say int 37. I want to convert it into hex 0x25 and than to get out from that hex std::string("25"). How to do such thing (using stl and boost)?
#include <sstream>
#include <iomanip>
#include <iostream>
int main() {
// To string:
std::ostringstream oss;
oss << std::hex << 37;
std::string result = oss.str();
std::cout << result << '\n';
// Back from string (if you need it):
std::istringstream iss(result);
int original;
if (!(iss >> std::hex >> original)) {
// handle error here
} else {
std::cout << original << '\n';
}
}
std::stringstream buffer;
buffer << std::hex << your_number;
buffer.str() will now give you a hex-representation of your number; If you want the 0x before the number, use this:
buffer << std::hex << showbase << your_number;
#include <sstream>
#include <iomanip>
std::ostringstream str;
str << "0x" << std::hex << length;
std::string result = str.str();
Demonstrated here.
Stringstreams are one way:
std::ostringstream ss;
ss << "0x" << std::hex << 12345;
std::string aString = ss.str();
An alternative is the all-mighty boost::format.
This would be a solution:
std::string convert_length_to_hex(const std::string& str)
{
std::ostringstream result;
result << std::hex << str.length();
return result.str();
}
Here is my example of dec to hex conversion and then back
#include <iostream>
#include <sstream>
#include <string>
#include <algorithm>
std::string dec2hex(int dec){
std::string result;
std::stringstream ss;
ss << std::hex << dec;
ss >> result;
std::transform(result.begin(), result.end(), result.begin(), ::toupper);
return result;}
int hex2dec(std::string& hex){
int x;
std::stringstream ss;
ss << std::hex << hex;
ss >> x;
return x;
}
int main()
{
std::string hex = "ABCD";
int dec = hex2dec(hex);
std::cout << dec << std::endl;
std::cout << dec2hex(dec) << std::endl;
return 0;
}
How can << be used to construct a string ala
int iCount;
char szB[128];
sprintf (szB,"%03i", iCount);
using namespace std;
stringstream ss;
ss << setw(3) << setfill('0') << iCount;
string szB = ss.str();
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>
using namespace std;
int main() {
int iCount = 42;
ostringstream buf;
buf << setw(3) << setfill('0') << iCount;
string s = buf.str();
cout << s;
}
How can << be used to construct a string ala
This doesn't make any sense.
Use std::ostringstream in C++ if you want to do the similar thing.
std::ostringstream s;
int x=<some_value>;
s<< std::setw(3) << std::setfill('0') <<x;
std::string k=s.str();