如何在iostream中处理浮点溢出

Ron*_*den 8 c++ iostream g++

我有一些非常简单的代码:

#include <iostream>
#include <sstream>
using namespace std;

int main()
{
  stringstream is("1.0 2.0 1e-500 1e500 12.0");
  double d = {17.0, 17.0, 17.0, 17.0, 17.0};

  for (int i=0; i < 5; ++i)
  {
    if (is >> d[i])
    {
      cout<<"Conversion succeeded"<<endl;
    }
    else
    {
      cout<<"Conversion failed"<<endl;
      is.clear();
    }
  }
  for (int i=0; i < 5; ++i) cout<<d[i]<<endl;
}
Run Code Online (Sandbox Code Playgroud)

当我使用g ++ 4.1.2编译此代码并在Redhat 5.10(相同的编译器)上运行时,我得到输出:

Conversion succeeded
Conversion succeeded
Conversion failed
Conversion failed
Conversion succeeded
1
2
0
17
17
12
Run Code Online (Sandbox Code Playgroud)

当我在Redhat Linux 6.5(编译器4.4.7)上执行相同的二进制文件时,我得到了

Conversion succeeded
Conversion succeeded
Conversion succeeded
Conversion failed
Conversion succeeded
1
2
0
1.79769e+308
12
Run Code Online (Sandbox Code Playgroud)

预期的行为是什么?下溢在4.4.7上成功,但在4.1.2上失败.溢出在4.4.7上失败(但仍然改变了值)并且在4.1.2时没有改变任何内容而失败.

行为是不确定的还是仅仅是不正确的?

Mik*_*our 3

根据 C++11 22.4.2.1.2,转换应该因溢出而失败,但不会因下溢而失败。在溢出的情况下,它仍然应该给出最大可表示值以及设置的值failbit

因此,您最新的编译器具有正确的现代行为。

然而,这两个古老的编译器都比 C++11 早很多年。在早期的标准中,转换被指定为如果scanf愿意则给出错误;并且在出现错误时不给出值。转向 C 标准,scanf遵循strtod,它又指定溢出错误;但下溢是否有错误是实现定义的。

所以你的旧编译器与历史行为是一致的。