解析libc ++和glibc中的双精度时不一致的字符串流行为

问题描述 投票:5回答:1

使用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,流的failbit ss.fail()没有设置,而
  2. 对于铿锵它是设定的

值得注意的是,在两种情况下,errno都设置为ERANGE

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

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

c++ parsing double stringstream
1个回答
1
投票

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

[istream.formatted.arithmetic]与插入器的情况一样,这些提取器依赖于语言环境的num_get<>([locale.num.get])对象来执行解析输入流数据。这些提取器表现为格式化的输入函数(如[istream.formatted.reqmts]中所述)。构造sentry对象后,转换就像执行以下代码片段一样:

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]有点冗长,但相关部分是:

对于double值,函数strtod。

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

strtod未在C ++标准中指定,但在C标准中未指定。相关位:

7.20.1.3 strtod,strtof和strtold函数

§10如果结果下溢(7.12.1),则函数返回一个值,该值的大小不大于返回类型中的最小归一化正数;是否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(简化)

当检测到微小的非零结果时,应发信号通知下溢异常。这应该是当指数范围和精度都无界时计算的非零结果严格地位于±bemin之间。

其中±bemin是最接近零的正或负法线值。它还说:

实施者应选择检测到的细微程度


所以,回答你的陈述:

我觉得它应该是一致的。

这样会很好,但是下溢的许多行为都被指定为实现定义的。

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

© www.soinside.com 2019 - 2024. All rights reserved.