如何检测非 IEEE-754 浮点数,以及如何使用它们?

How to detect non IEEE-754 float, and how to use them?

我正在为基本类型编写 类,因此代码在多个平台和编译器上在逻辑上是相同的(例如 int_least16_tint)。为了娱乐! (我还是个学生。) 我读了这个:

float [...] Matches IEEE-754 binary32 format if supported.

更糟糕的是:

Floating-point types MAY support special values: , NaN or -0

这意味着 float 可以 是无符号的...
[编辑:是的,这是不同的东西,但没有:“,但必须支持负数”。哟,在标准中没有这样的东西它可能不支持正常的 0 ...(我没有规范。)]

我知道这和 __int128 一样,标准只是标准, 但还是... IEEE-754 是 1985 年的,但有些机器可能很奇怪, 一些旧硬件没有浮动单元。

据我了解,浮动是强制性的(不像int16_t那样是可选的), 但可以在任何标准中,并且可以是任何一组值?


我们只有一些宏 (<cfloat>):

如果浮点数类似于 IEEE-754(符号、指数、分数),那么很容易, 但如果 -0 和 NaN 是可选的,那么它 可能 不同。 因为我不能区分它们,所以我不能使用位表示 (以安全的方式)。而如果 是可选的,那么 float 就不再是安全类型了。

我看到的唯一出路是向编译器添加宏。

我知道这是一个理论上的问题,但我很感兴趣是否可以进行任何检查,或者我们都编写了依赖于实现的代码,当我们使用 float 关键字时?


编辑 2022 年 5 月 4 日:

我想到了这个:

用户例如。代码:

//User eg. code:

int main()
{
   float_M a = 1f;
   float_M b = 0f;
   std::cout << a/b; //should output infinty (IEEE-754)
}

//Code:

class float_M
{
public:
#ifdef __STDC_IEC_559__
   float data;
//...
   float_M operator/(float_M x){return float_M(data/x.data);}
//...
#else
   /*union{
      float data;
      struct{//For noSign case ("absolutly catastrofic" case)
         uint_least8_t sign : 1;
         uint_least8_t exponent : 8;
         uint_least32_t fraction : 23;
      }
   }*/ //no noSign case 
   float data;
//...
   float_M operator/(float_M x){return divide(this, x);}

//funtion pointer alert!
   static /*const (1*) */ float_M (*divide)(float_M a, float_M b) =
      /*std::numeric_limits<float>::is_signed ?(*/
         std::numeric_limits<float>::has_infinity ?(
            std::numeric_limits<float>::has_quiet_NaN ?(
               []{return float_M(a.data/b.data);}
            ): &_divide_noNaN
         ): &_divide_noNaN
      /*): &_divide_noSign*/
//...
#endif
}

它很丑(有函数指针),但可以防止在运行时发生错误的跳转。希望c++23有更好的宏

此外,更多链接:

跟进:

在C++中,std::numeric_limits<T>::is_iec559 shall be true for all floating-point types T "if, and only if, the type adheres to ISO/IEC/IEEE 60559"和ISO/IEC/IEEE60559:2011的值与IEEE 754-2008相同,所以:

#include <iostream>
#include <limits>

int main() {
    std::cout << std::boolalpha << std::numeric_limits<float>::is_iec559 << '\n';
}

注意:如评论中所述,某些实现可能仍会报告此常量的 true,即使它们的浮点类型不严格遵循 IEEE 754-2008 标准。

例如,在 gcc 中,您可以使用选项 -Ofast-ffast-math 进行编译,这反过来会设置许多选项,这些选项可能会导致依赖于程序的输出不正确关于数学函数的 IEEE 或 ISO rules/specifications 的精确实现。


C99(及更高版本)中,有条件特征宏 __STDC_IEC_559____STDC_IEC_559_COMPLEX__,如果在您的实现中可用,将告诉您它是否符合 IEC 60559:1989 / IEEE 754−1985.

#include <stdio.h>
int main(void) {
#ifdef __STDC_IEC_559__
    puts("true");
#endif
}

请注意,如果 __STDC_IEC_559__ 未定义 ,则不一定意味着该实现不使用 IEEE 754 浮点数。这可能只是意味着它没有这些条件特征宏。关于这些宏的一个有趣的注意事项是,如果您在 gcc 中使用 -Ofast-ffast-math,它们将不会被定义(与 C++ 测试不同)。

C11 and C17/18 and in C23(草案)中使用的 IEC / IEEE 标准的实际修订版发生了变化,将会有许多与浮点相关的新宏,它(当前)指的是 ISO/IEC60559:2020 和 IEEE 754-2019,其中包含对 IEC 60559:2011 / IEEE 754-2008 的微小升级。