FMA 和朴素 a*b+c 的区别?

Difference between FMA and naive a*b+c?

在 FMA(3) 的 BSD 库函数手册中,它说 "These functions compute x * y + z."

那么 FMA 和执行 x * y + z 的原始代码有什么区别?为什么FMA在大多数情况下有更好的表现?

a*b+c 产生的结果就好像计算是:

  • 计算ab的无限精确乘积。
  • 将该产品四舍五入为正在使用的 floating-point 格式。
  • 计算该结果和 c 的无限精确总和。
  • 将总和四舍五入为正在使用的 floating-point 格式。

fma(a, b, c) 产生的结果就好像计算是:

  • 计算ab的无限精确乘积。
  • 计算该乘积与 c 的无限精确总和。
  • 将总和四舍五入为正在使用的 floating-point 格式。

因此它跳过了将中间产品四舍五入为floating-pint格式的步骤。

在带有 FMA 指令的处理器上,融合 multiply-add 可能更快,因为它是一条 floating-point 指令而不是两条,而且硬件工程师通常可以设计处理器以高效地执行此操作。在没有 FMA 指令的处理器上,融合 multiply-add 可能会更慢,因为软件必须使用额外的指令来维护获得所需结果所需的信息。

[我没有足够的业力来发表评论;添加另一个答案似乎是唯一的可能性。 ]

Eric 的回答很好地涵盖了所有内容,但需要注意:有时使用 fma(a, b, c) 代替 a*b+c 会导致难以诊断的问题。

考虑

x = sqrt(a*a - b*b);

如果换成

x = sqrt(fma(a, a, -b*b));

对于 ab 的值,sqrt 函数的参数可能为负,即使 |a|>=|b| 也是如此。特别是,如果 |a|=|b| 并且无限精确乘积 a*a 小于 a*a 的舍入值,则会发生这种情况。这是因为计算 a*a 时的舍入误差由 fma(a, a, -a*a).

给出