在libc ++和glibc中解析双精度时出现不一致的stringstream行为

时间:2019-02-12 14:25:12

标签: c++ parsing double stringstream

使用gccclang编译以下示例时...

#include <sstream>
#include <iostream>

int main() {
    double val;
    std::stringstream ss("6.93758e-310");
    ss >> val;

    std::cout << "fail: " << ss.fail() << std::endl
}

...我得到不同的行为:

  1. 使用gcc时,未设置流的故障位ss.fail(),而
  2. 设置叮当声

可能需要注意的是,在两种情况下,errno都设置为ERANGE

另外,在本地,我对clang和gcc的行为相同,除非我明确地将libc ++与clang(-stdlib=libc++)而不是glibc一起使用。

我不确定正确的行为是什么,但是我觉得应该保持一致。

1 个答案:

答案 0 :(得分:1)

输入流提取运算符的行为指定如下:

  

[istream.formatted.arithmetic]与插入程序一样,这些提取器取决于语言环境的num_get<>([locale.num.get])对象   执行解析输入流数据。这些提取器表现为格式化的输入函数(例如   在[istream.formatted.reqmts]中进行了介绍)。构造哨兵对象后,转换就好像由   以下代码片段:

using numget = num_get<charT, istreambuf_iterator<charT, traits>>;
iostate err = iostate::goodbit;
use_facet<numget>(loc).get(*this, 0, *this, err, val);
setstate(err);
     

在上面的片段中,loc代表basic_ios类的私有成员。

[facet.num.get.virtuals]有点冗长,但是相关的部分是:

  

对于双精度值,该函数为strtod。

     

...如果该字段表示的值超出可表示的值的范围,则ios_base :: failbit   分配给err。

strtod不是在C ++标准中指定的,而是在C标准中指定的。相关位:

  

7.20.1.3 strtod,strtof和strtold函数

     

§10如果结果下溢(7.12.1),则这些函数返回一个其大小不大于返回类型中最小的规范化正数的值;否则,返回0。 errno是否获取值ERANGE是实现定义的。

引荐规则:

  

7.12.1错误条件的处理

     

§5如果数学结果的大小如此之小,以至于在没有特殊舍入误差的情况下,无法在指定类型的对象中表示数学结果,则结果将下溢。 204)结果下溢时,该函数返回实现定义的值,其值不大于指定类型中的最小归一化正数;如果整数表达式math_errhandling&MATH_ERRNO非零,则errno是否获取值ERANGE是实现定义的;如果整数表达式math_errhandling&MATH_ERREXCEPT不为零,则是否实现“下溢”浮点异常是由实现定义的

     

204)此处的下溢一词旨在涵盖IEC 60559中的“渐进式下溢”和“冲洗至零”下溢。


尽管C ++没有指定浮点运算的表示方式,但是您的系统可能使用IEEE-754(IEC 60559)。

IEEE-754将下溢指定为:

  

7.5.0(简体)

     

当检测到微小的非零结果时,应发出下溢异常的信号。当指数范围和精度都不受限制的非零结果严格位于±b emin 之间时。

其中±b emin 是最接近零的正或负 normal 值。它还说:

  

实施者应选择如何检测小


因此,请回答您的声明:

  

在我看来,它应该是一致的。

那很好,但是将下溢周围的许多行为指定为实现定义。

坦率地说,输入流API受约束,因为在检测到下溢的情况下,它不能提供对舍入值的保证访问,也不能提供区分下溢故障和其他故障的方法。 / p>