【问题标题】:What is the fastest way to write a IEEE-754 compliant double/float division in C++?在 C++ 中编写符合 IEEE-754 的双/浮点除法的最快方法是什么?
【发布时间】:2017-06-23 09:23:13
【问题描述】:

我想用 C++ 编写一个符合 IEEE-754 的除法,特别是关于除零处理:positive/0->Infnegative/0->-Infeverything else/0->NaN

虽然我的机器上的一个简单的 C++ 除法会导致这种行为,但 C++ 标准并不强制要求这种语义。相反,它是未定义的,所以我不能依赖它。

那么在 C++ 中实现它的最快方法是什么?当然,我可以像这样进行显式测试:

double fdiv64(double numerator, double denominator)
{
   using limits=std::numeric_limits<double>;
   if (denominator==0.0) {
      if (numerator>0.0) {
         return limits::infinity();
      } else if (numerator<0.0) {
         return -limits::infinity();
      } else {
         return limits::quiet_NaN();
      }
   } else {
      return numerator/denominator;
   }
}

但这引入了额外的分支,在我的机器上完全是多余的,因为无论如何我都得到了正确的行为。似乎没有执行 IEEE-754 兼容划分的编译器内在函数。我可以使用内联汇编,但这也很不方便。

那么进行这种划分的最快方法是什么?

【问题讨论】:

  • 语言标准不可能包括和跟踪IEEE-754标准。 stackoverflow.com/a/30245885/412080
  • 在已经这样做的硬件上运行它。严重地。主流平台已经在做 AFAIK。
  • 请注意,在可移植 C++ 中,您甚至不能假设浮点值的 格式 是 IEEE-754。 float 可以是 42 位。因此,您天生就处于非便携式领域;唯一的问题是多远。
  • @gexicide 预期但例外。你不应该除以零。 IEEE-754 将这些值定义为 exceptional 并使用它们在下溢的情况下保留符号。您已经在以不合规的方式使用这些值。
  • 您可以使用std::numeric_limits&lt;double&gt;::is_iec559 进行检查。 (IEC 559 是 IEEE 754 的别称)

标签: c++ division undefined-behavior ieee-754 divide-by-zero


【解决方案1】:

恐怕你不能以便携的方式做到这一点,除非你在软件中为本身不使用它的平台构建自己的 IEEE754 浮点实现,即使那样也会有细微的差异,因为你的类型会不是内置类型(例如 &amp;&amp;|| 如果重载它们不会短路);虽然用户定义的文字可能会有所帮助。

例如,对infinity 的支持是可选的,并且仅当std::numeric_limits&lt;T&gt;::has_infinity == true 为您的类型T 时才会出现在平台上。

因此,尝试优化您所谓的可移植代码甚至不在桌面上。

参考资料:

http://en.cppreference.com/w/cpp/types/numeric_limits/infinity http://en.cppreference.com/w/cpp/language/user_literal

【讨论】:

  • 除法不是依赖于处理器吗?
  • @PanagiotisKanavos:这些天是的。
  • 8-bit microcontrollers 除外,例如一些 Arduino 板中使用的那些。
  • 你会为自己的浮点类型重载&amp;&amp;吗?!
  • @MSalters:不太可能,但我做得更糟。说真的,在这种情况下,您可能需要实现 NaN。没想到这么多。
【解决方案2】:

您可能已经拥有它,而无需做任何特别的事情。在几种架构上,您可以指定 CPU 在“特殊”情况下应该做什么(除以零等)。看看fesetenv。编译器通常会切换它们应该如何处理浮点数学。例如,看看 Visual Studio 的 cl.exe option 关于它。

如果您继续使用 x86 架构(并使用内部精度设置为浮点/双精度的 SSE 或 x87,请参阅下面的链接了解详细信息),我认为您可以依赖 IEEE754 开箱即用的行为(这样您的程序就可以工作在任何 x86 机器上,而不仅仅是您的机器上)。

如果您的 CPU 不能遵循 IEEE754,那么您可能必须使用完整的软件浮点实现。或者你可以使用硬件,只需要处理特殊情况。

但通常,今天,几乎所有东西(PC、移动设备)都使用 IEEE754:

在 SW 实现中,您必须从浮点数中提取符号、指数、尾数,然后自己进行数学运算。

注意:即使除数不为零,而是一个小(次正规)数时,您也可以得到 inf 结果。这是因为最大。浮点数在 ~10^38 范围内,但最小但正数在 ~10^-45 范围内。

【讨论】:

  • 第二个链接指出几乎所有东西都使用 IEEE754 layout,但大多数实现都违反了一些规则。对于边缘情况尤其如此,例如这个问题中的情况。
  • @MSalters:我在答案中添加了要点。你知道不兼容IEEE754的常用CPU吗?游戏机有时不完全兼容(PS2 VU 在乘法时出现 1 ulp 错误,PS3 的 SPU 也不完全兼容,但这些影响到的程序员很少)
  • AFAIK ARM VFP 在硬件上不兼容 IEEE754(“RunFast”模式),但可以使用中断和软件支持来完全实现 IEEE754。
猜你喜欢
  • 2016-12-07
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 2013-06-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多