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

Ale*_*icz 4 c c++ legacy floating-point standards

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

\n
\n

float [...] 匹配 IEEE-754 binary32 格式(如果支持)。

\n
\n

更糟糕的是:

\n
\n

浮点类型可以支持特殊值:\n \xe2\x88\x9e、 NaN 或 -0

\n
\n

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

\n

我知道这就像__int128一样,标准只是一个标准,\n但仍然...\nIEEE-754 是 1985 年的,但有些机器可能很奇怪,\n而且一些旧硬件没有浮动单位。

\n

据我了解, float 是强制性的(不像 int16_t 那样是可选的),\n但可以在任何标准中,并且任何值集都可以吗?

\n
\n

我们唯一拥有的就是一些宏 ( <cfloat>):

\n
    \n
  • FLT_MIN, FLT_MAX- 即使FLT_MIN = IEEE-754::FLT_MIN, float 也可以是非 IEEE-754。\n例如 float:带有分数的翻转指数...

    \n
  • \n
  • FLT_RADIX- 基础系统?如果是这样,可以帮忙写出准确的值。但是,float 仍然可以是 3 位或 200 位(大小)...

    \n
  • \n
  • FLT_EPSILON-(从 1 到下一个)我们可以使用它(带基数)来检查分数大小......

    \n
  • \n
  • FLT_MANT_DIG- 是“尾数”数字/分数大小吗?

    \n
  • \n
  • FLT_MAX_EXP- IEEE-754 中指数用 1... 填充,\n但外面可以是随机数吗?

    \n
  • \n
\n

如果 float 就像 IEEE-754(符号、指数、分数),那么这很容易,\n但是如果 -0 和 NaN 是可选的,那么它可能会不同。\n因为我无法区分它们,所以我可以\n(以安全的方式)使用位表示。如果\xe2\x88\x9e是可选的,float则不再是安全类型。

\n

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

\n

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

\n
\n

2022年5月4日编辑:

\n

我想出了这个:

\n

用户例如。代码:

\n
//User eg. code:\n\nint main()\n{\n   float_M a = 1f;\n   float_M b = 0f;\n   std::cout << a/b; //should output infinty (IEEE-754)\n}\n\n//Code:\n\nclass float_M\n{\npublic:\n#ifdef __STDC_IEC_559__\n   float data;\n//...\n   float_M operator/(float_M x){return float_M(data/x.data);}\n//...\n#else\n   /*union{\n      float data;\n      struct{//For noSign case ("absolutly catastrofic" case)\n         uint_least8_t sign : 1;\n         uint_least8_t exponent : 8;\n         uint_least32_t fraction : 23;\n      }\n   }*/ //no noSign case \n   float data;\n//...\n   float_M operator/(float_M x){return divide(this, x);}\n\n//funtion pointer alert!\n   static /*const (1*) */ float_M (*divide)(float_M a, float_M b) =\n      /*std::numeric_limits<float>::is_signed ?(*/\n         std::numeric_limits<float>::has_infinity ?(\n            std::numeric_limits<float>::has_quiet_NaN ?(\n               []{return float_M(a.data/b.data);}\n            ): &_divide_noNaN\n         ): &_divide_noNaN\n      /*): &_divide_noSign*/\n//...\n#endif\n}\n
Run Code Online (Sandbox Code Playgroud)\n

它很丑(有函数指针),但可以防止运行时不必要的跳转。希望c++23有更好的宏。

\n

另外,更多链接:

\n\n

后续:浮动可以不支持负数吗

\n

Ted*_*gmo 6

在 C++ 中, 的值std::numeric_limits<T>::is_iec559适用true于所有浮点类型T “当且仅当该类型遵守 ISO/IEC/IEEE 60559”并且 ISO/IEC/IEEE 60559:2011 与 IEEE 754-2008 相同时,所以:

\n
#include <iostream>\n#include <limits>\n\nint main() {\n    std::cout << std::boolalpha << std::numeric_limits<float>::is_iec559 << \'\\n\';\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

例如,在 中gcc,您可以使用选项进行编译-Ofast,或者-ffast-math依次设置多个选项,这可能会导致依赖于数学函数的 IEEE 或 ISO 规则/规范的精确实现的程序输出不正确。

\n
\n

C99(及更高版本)中,有条件功能宏,__STDC_IEC_559__并且__STDC_IEC_559_COMPLEX__,如果在您的实现中可用,它将告诉您它是否符合 IEC 60559:1989 / IEEE 754\xe2\x88\x921985。

\n
#include <stdio.h>\nint main(void) {\n#ifdef __STDC_IEC_559__\n    puts("true");\n#endif\n}\n
Run Code Online (Sandbox Code Playgroud)\n

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

\n

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

\n

  • @Turtlefight:这就是 C++“未定义行为”的工作原理。如果 C++ 标准规定行为未定义,则任何结果都是可接受的。因此“无穷大”也是可以接受的。这不仅仅是 C++ 与 IEEE754 的对比;C++ 和 POSIX 也有类似的东西。 (3认同)