你可以使用stringstream安全地双向转换吗?

时间:2014-06-19 13:45:55

标签: c++ formatting stringstream

我有这种情况,使用stringstream将double转换为字符串。现在,我必须在其他地方取回该值(不,我无法访问原始的double),所以我必须解析格式化的字符串。

当然,我也可以用字符串流来读它,但这样安全吗?对于所有价值观,它总能奏效吗?

std::ostringstream doubleToString;
double myDouble = 3.14;
doubleToString << myDouble;
std::string convertedDouble = doubleToString.str();

std::istringstream stringToDouble(convertedDouble);
double newDouble;
stringToDouble >> newDouble;

在上面的例子中,myDouble总是等于newDouble吗?

注意:边际差异(0.00000000001)不是我关注的问题。

1 个答案:

答案 0 :(得分:4)

不,它不会一直有效。您可以使用代码的这种微小修改来证明这一点:

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

当我在我的机器上运行此代码时,我得到了这个输出:

convertedDouble = inf
newDouble = 0
xlat: xlat.cpp:19: int main(): Assertion `newDouble == myDouble' failed.
Aborted (core dumped)

更新

请注意,如果您始终以特定计算机上可表示的浮点数范围内的双精度(即std::numeric_limits<double>::min() <= x <= std::numeric_limits<double>::max())开头,则仍无法保证。作为示例,请使用double myDouble = 1/3.0;尝试上面的代码。将double发送到字符串时,问题是精度问题。我们可以尝试通过修改代码来解决这个问题:

doubleToString << 
    std::setprecision(std::numeric_limits<double>::digits10) << myDouble;

这具有将精度设置为整数值所需的十进制数字的效果,该整数值将始终在转换为double之后生存。但是,它仍然不适用于所有双值!

double myDouble = pow(1/3.0, 300);

该值将导致断言触发。原因是digits10只是对于浮点数的尾数部分而言并且不代表指数。在这里完全迂腐,我们可以将正确的值设置为:

constexpr int dblprecision = std::numeric_limits<double>::digits10 
        + ceil(log10(std::numeric_limits<double>::max_exponent10));
doubleToString << std::setprecision(dblprecision) << myDouble;

请注意,这只需要在双到字符串转换方向,而不是其他方式。

因此理解输入值必须在指定的范围内,并且如果设置转换为字符串的精度,我认为这将始终导致原始的double,假设没有编译器或库的实现中的错误。