atof 和 stringstream 产生不同的结果

atof and stringstream produce different results

我一直在研究将浮点数转换为人类可读格式并返回的问题。即一个字符串。我 运行 使用 stringstream 遇到问题,发现 atof 产生 "better" 结果。

注意,在这种情况下我没有打印出数据,我使用调试器检索值:

    const char *val = "73.31";
    std::stringstream ss;
    ss << val << '[=10=]';
    float floatVal = 0.0f;
    ss >> floatVal; //VALUE IS 73.3100052

    floatVal = atof(val); //VALUE IS 73.3099976

对此可能有一个合理的解释。如果有人能启发我,我将不胜感激:)。

答案是基于OP使用MSVC的假设

atof 在读取浮点值方面确实比 istream.

更好

看这个例子:

#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;
}

输出:

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

编译器甚至会警告从 doublefloat 的转换:

warning C4244: '=': conversion from 'double' to 'float', possible loss of data

我还找到了这个页面:Conversions from Floating-Point Types


更新:

73.3099975585938 似乎是对 double73.31 的正确 float 解释。


更新: istream>>(double&) 也能正常工作:

#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;
}

输出:

istream>>(double&) :             73.31

对于算术类型 istream::operator>> 使用 num_get::getnum_get::get 应该为 float source

使用类似 scanf("%g") 的东西

但是:

#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;
}

输出:

73.3099975585938

对我来说,这看起来可能是 Microsoft 中的一个错误 num_get