【问题标题】:How is floating point overflow handled in iostreamsiostreams 中如何处理浮点溢出
【发布时间】:2014-09-12 14:32:46
【问题描述】:

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

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

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

Conversion succeeded
Conversion succeeded
Conversion failed
Conversion failed
Conversion succeeded
1
2
0
17
17
12

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

Conversion succeeded
Conversion succeeded
Conversion succeeded
Conversion failed
Conversion succeeded
1
2
0
1.79769e+308
12

预期的行为是什么?下溢在 4.4.7 上成功,但在 4.1.2 上失败。溢出在 4.4.7 上失败(但仍会更改值),并且在 4.1.2 上失败而不更改任何内容。

其中一个行为是否未定义或根本不正确?

【问题讨论】:

  • 好问题。 &gt;&gt; 是根据strtold 的规则间接(通过num_get)定义的,对于后者,明确未指定是否将下溢视为错误条件。但是,下溢不被视为num_get 的错误条件之一。我不确定这是否意味着它未指定,或明确定义为成功返回 0。

标签: c++ g++ iostream


【解决方案1】:

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

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

但是,您的两个古老编译器都比 C++11 早了很多年。在早期的标准中,如果scanf 会出现错误,则指定转换;并且在出错的情况下不给出值。转向 C 标准,scanf 遵循strtod,后者又指定溢出错误;但是下溢是否有错误是实现定义的。

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

【讨论】:

    猜你喜欢
    • 2013-07-10
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2020-09-06
    • 2023-03-16
    • 1970-01-01
    • 2018-02-17
    • 1970-01-01
    相关资源
    最近更新 更多