编译器使用的双精度表示的明确规范

时间:2018-11-19 13:21:23

标签: c++ gcc visual-c++ clang

我最近遇到了一个问题,即visual-c++似乎不符合IEEE 754,而是使用subnormal representation。也就是说,其中的双精度浮点数通常不表示1个符号位,11个指数位和52个显式存储的有效十进制位,请参见下文。

由于gccclang是兼容的,因此非常需要一致的跨平台行为,我想知道是否有可能强制visual-c++使用正常表示。另外,使gccclang使用次正规表示当然也可以解决问题。

可以使用以下代码在visual-c++gccclang中重现不同的双重表示形式的问题:

#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}}的行为始终如一,而无需为其实现单独的包装。

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