Atof and stringstream give different results

I was looking for a problem due to which I convert float to a human-readable format and vice versa. Namely a string. I ran into problems using stringstream and found that atof produces the "best" results.

Please note: I do not print the data in this case, I used a 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 

Perhaps this is a reasonable explanation. If anyone can enlighten me, I would be great :).

+5
source share
1 answer

The answer is based on the assumption that the OP uses MSVC

atof really better to read 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 converting from double to 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 interpretation of the float value of double 73.31 .


Update: istream>>(double&) works correctly:

 #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>> num_get::get . num_get::get should use 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 it seems like a bug in Microsoft num_get

+2
source

All Articles