我最近遇到了一个问题,即visual-c++
似乎不符合IEEE 754,而是使用subnormal representation。也就是说,其中的双精度浮点数通常不表示1个符号位,11个指数位和52个显式存储的有效十进制位,请参见下文。
由于gcc
和clang
是兼容的,因此非常需要一致的跨平台行为,我想知道是否有可能强制visual-c++
使用正常表示。另外,使gcc
和clang
使用次正规表示当然也可以解决问题。
可以使用以下代码在visual-c++
,gcc
和clang
中重现不同的双重表示形式的问题:
#include <iostream>
#include <string>
int main()
{
try {
std::stod("8.0975711886543594e-324");
std::cout << "Subnormal representation.";
} catch (std::exception& e) {
std::cout << "Normal representation.";
}
return 0;
}
在所有三种情况下,表示规范是否都能产生一致的行为?
编辑:正如geza所指出的那样,在std::stod
的不同实现中这似乎是一个问题,这将使人们产生疑问,是否有任何方法可以制作{ {1}}的行为始终如一,而无需为其实现单独的包装。
答案 0 :(得分:3)
不幸的是,std::stod
的设计很糟糕,因为无法确定是什么原因导致了std::out_of_range
异常。
我建议您改用strtod
。虽然标准中未指定此函数对次标准数字应执行的操作,但通常对于次标准数字表现良好(这意味着它将返回次标准数字)。此功能的好处是,对于超出范围的情况,它可以返回有意义的结果,因此可以确定超出范围的原因。
如果要处理超出范围的情况,则需要检查errno
中是否有ERANGE
。请注意,如果得出的结果是一个非标准数/零数,则errno
可能会设置为ERANGE
,您应该忽略该值(可以使用fpclassify
进行检查)。>
所以逻辑是这样的:
double r = strtod(string, &end);
// here, check for end to know about invalid strings
if (errno==ERANGE) { // out-of-range (overflow, underflow)
int c = fpclassify(r);
if (c!=FP_SUBNORMAL&&c!=FP_ZERO) { // let's filter out underflow cases
// "real" out of range handling here, just overflow
}
}