你可以使用stringstream安全地进行双向类型转换吗?

5
我有一个问题,涉及到将double类型通过stringstream转换为字符串。现在,我必须在另外一个地方获取该值(不幸的是,我没有访问原始double值的权限),因此我必须解析格式化后的字符串。
当然,我也可以使用stringstream来读取它,但这样做是否安全?对于所有值,它是否总是有效的?
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个回答

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 值都不适用!

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;

请注意,这仅适用于双精度转换为字符串的方向,而不是反过来。
因此,在理解输入值必须在指定范围内的前提下,并且设置了转换为字符串的精度,我认为,假设编译器或库的实现没有错误,这将始终导致原始双精度。

非常好的例子!在我的情况下,我可以依赖于我从有效的双精度数开始。没有像inf这样的奇怪现象:)。那么,考虑到这一点,它仍然不安全吗? - W. Goeman
@W.Goeman:我已在答案的更新中回答了那个问题。 - Edward
太好了,这就是我想知道的全部内容。非常感谢。 - W. Goeman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接