#include <sstream>
#include <iostream>
int main() {
double val;
std::stringstream ss("6.93758e-310");
ss >> val;
std::cout << "fail: " << ss.fail() << std::endl
}
......我得到不同的行为:
ss.fail()
没有设置,而值得注意的是,在两种情况下,errno
都设置为ERANGE
。
另外,在本地我得到了与clang和gcc相同的行为,除非我明确地使用libc ++与clang(-stdlib=libc++
)而不是glibc。
我不确定正确的行为是什么,但我觉得它应该是一致的。
输入流提取运算符的行为指定如下:
[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受到约束,因为它在检测到下溢的情况下不提供对舍入值的保证访问,也没有提供区分下溢故障与其他故障的方法。