【问题标题】:How to make my C++ library compliant with IEEE 754如何使我的 C++ 库符合 IEEE 754
【发布时间】:2026-02-04 07:25:01
【问题描述】:

我已经编写了一个小型库(在 C++11 中)来计算四元数,但我很快意识到存在许多精度/准确性问题,因为涉及到很多浮点运算。这让我开始研究 std::complex 和 IEEE 754。std::complex 在处理 NaN 方面做了相当多的工作。这是我唯一需要担心成为“IEEE 754 兼容”的事情吗?更一般地说,是否有一个“秘诀”可以将原本幼稚的数值库转变为“符合 IEEE 754”的库?

注意:问题不在于编译器是否是IEEE 754,而在于我是否应该在自己的算法中采取特殊步骤来满足IEEE 754。毕竟我是同一个位置作为编写 std::complex 的人,他们确实采取了额外的步骤,例如对于 NaN。

【问题讨论】:

  • 旁注:如果您关心速度,请注意poor performance of std::complex
  • 谢谢!确实——所以我打算让 IEEE 754 一致性成为可选的。但是英特尔的一篇论文(当然!)警告我,如果我的库不是 IEEE-754,就会发生火箭坠毁等等。
  • 四元数运算(如乘法)通常处理(有符号)乘积的运行总和。您可以将Kahan summation 视为一种相对便宜的方法来提高符合 IEEE-754 的准确性。您还可以查看一个相对成熟的实现,例如 Boost 的四元数类。我想像分支切割等复杂的概念,如果你想保持一致的话,在理论上会用四元数变得更加陌生。
  • 另请注意,如果您使用四元数进行旋转,则应在应用操作后(重新)规范化它们,以将它们保持为“单位”旋转。

标签: c++ c++11 floating-point numeric ieee-754


【解决方案1】:

您可以简单地检查您的库的 Header <limits> 常量 numeric_limits::is_iec559(IEC 559 与 IEEE 754 相同)来查看您的 C++ 编译器是否已经支持 IEEE 754。

【讨论】:

  • Paul - 是的,确实如此,但这似乎并不是故事的结局。例如,如果你看一下 std::complex 库,它有处理 NaN 的代码 - 所以我认为作为一名程序员,我必须在我的算法可以产生 NaN 的任何地方添加类似的代码。
【解决方案2】:

使算术符合 IEEE 标准不是您的任务,而是编译器的任务。

您的编译器要么符合 IEEE,要么不符合 IEEE (@Paul),您对此无能为力。具体来说,您不能使用符合 IEEE 的编译器双算术编写不符合 IEEE 的程序(请不要相信我的话 :))。这与您几乎无法使用符合 ISO/IEC 14882:2011 的编译器编写不符合 ISO/IEC 14882:2011 的程序类似。

然而,这并不能确保程序给出预期的输出并且它没有奇怪的操作,包括 UB。这类似于 NaN 和 INF 在 IEEE 754 中发挥作用的地方。它们可以对定义不明确的数学运算(例如 0/0)或超出范围的运算(例如 1/0)给出“合理的答案”。

标准并不关心您如何在库中处理这些答案(即如何将它们翻译给 lib 用户)。该标准仅规定了如何在另一个数学运算中使用这些“合理答案”给出另一个“合理答案”。

您可能对http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf 感兴趣(阅读难度很大,但至少为了抓住这个想法值得付出努力)

Ps 我检查了我的 lib 实现(MinGW 4.9.1. 32 位),并没有注意到那里有任何 NaN 魔法。

【讨论】:

  • 如果每次有人提到 Goldberg 论文作为浮点问题的最后一句话,我就有一美元......
  • @PavDub - 检查 std::complex 的 gcc 实现。我在那里看到了一些 NaN 的特殊代码。我还看到一个德国人的演示文稿,他抱怨这种额外的处理使他的计算——他可以证明永远不会产生 NaN——太慢了。
  • @Frank 我没有逐行完成复杂的实现,但乍一看没有注意到任何 NaN 的痕迹。你能把你的实现发给我吗?不是我不相信你,而是我只是好奇......(我的在这里:link
  • 我在 Mac 上使用的是:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/complex。
  • 我稍后会在 pastebin 上发布一个 sn-p - 我无法从工作中访问 pastebin。 template complex<_tp> operator*(const complex<_tp>& __z, const complex<_tp>& __w) 使用了很多 isinf 和 isnan。
【解决方案3】:

[@Frank : cmets 低于我 8 月 3 日 7:38 的最后一个答案]

当复数相乘时,NaN 可能是 - 使用 uploaded by @Frank - PasteBin 处的 XCode iplementation 表示法的结果:

__x is NaN if any of __a, __b, __c, __d is Nan or
__ac == +INF && __bd == +INF or
__ac == -INF && __bd == -INF or
__a == (+/-)INF && __c == 0 or *vice versa* or
__b == (+/-)INF && __d == 0 or *vice versa* or

__y is NaN if any of __a, __b, __c, __d is Nan or
__ad == -INF && __bc == +INF or
__ad == +INF && __bc == -INF or
__a == (+/-)INF && __d == 0 or *vice versa* or
__b == (+/-)INF && __c == 0 or *vice versa* or

然后他们(XCode STL 作者)玩弄这些以允许诸如

之类的情况
(INF + INFi)*(c + di)
(INF + INFi)*(0 + 0i)
etc...

诀窍(最有可能)是将包含 INF 和 NaN 的值设置为 (+/-)1 或 (+/-)0,以便最终重新计算

if (__recalc)
{
    __x = _Tp(INFINITY) * (__a * __c - __b * __d);
    __y = _Tp(INFINITY) * (__a * __d + __b * __c);
}

结果

INF * (+/-)INF = (+/-)INF or
INF * (+/-)0   = NaN

视情况而定。

这是

如何将它们翻译给 lib 用户

ps.>我没有时间深入研究这个问题,因此我可以判断他们的实施,但它很可能是合理的。 (这个Math forum link 很有帮助,但我无法轻松地将其转换为 [a+bi] 复数符号)无论如何,MinGW 4.9.1。 32 位 Win 实现使该任务保持打开状态,用户应处理极端情况。您可以首先采用 MinGW 策略,或者如果您知道如何正确处理四元数代数的极端情况,则可以采用 XCode 策略。无论如何,这不再是关于如何使我的 C++ 库符合 IEEE 754 ...

【讨论】:

  • 这就是这个线程的起源:我查看了他们为 std::complex 所做的事情,这让我开始思考是否应该处理他们在我自己的操作中处理的所有案例,如果这需要“符合 IEEE-754”:我认为这个标准描述了在这些极端情况下的预期 - 那是我的错误。