atof and stringstream produce different results

陌路散爱 提交于 2019-12-05 11:06:21

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!