【问题标题】:Is there any scenario where function fma in libc can be used?有没有可以使用 libc 中的函数 fma 的场景?
【发布时间】:2012-10-28 19:47:54
【问题描述】:

我遇到this page,发现有一个奇怪的浮动乘加函数 --fmafmaf。它说结果是这样的:

 (x * y) + z             #fma(x,y,z)

并且值是无限精度并四舍五入到结果格式

但是,AFAICT 我以前从未见过这样的三元运算。所以我想知道这个函数的自定义用法是什么。

【问题讨论】:

标签: c floating-point posix libc fma


【解决方案1】:

fused-multiply-add 指令的重要方面是(实际上)中间结果的无限精度。这有助于提高性能,但不是因为两个操作被编码在一条指令中 - 它有助于提高性能,因为中间结果的几乎无限精度有时很重要,而且用普通的方法恢复非常昂贵当这种精度级别确实是程序员所追求的时,乘法和加法。

示例:比较 a * b1.0

假设对于算法而言,确定两个双精度数 ab 的乘积相对于非零常数的位置至关重要(我们将使用 1.0)。数字ab 都具有二进制数字的完整有效位。如果您将a*b 计算为double,则结果可能是1.0,但这并不能告诉您实际的数学乘积是略低于1.0 并四舍五入为1.0,还是略高于1.0 并向下舍入。如果没有 FMA,您的选择是:

  1. a*b 计算为四精度数。四精度不在硬件中实现,但有软件仿真库。在四精度中,乘积的数学结果可以精确表示,然后您可以将其与 1.0 进行比较。

  2. 在向上舍入模式和向下舍入模式下以双精度计算 a*b。如果两个结果都是 1.0,则意味着 a*b 正好是 1.0。如果 RU(a * b) 大于 1.0,则表示数学乘积高于 1.0,如果 RD(a * b) 低于 1.0,则表示数学乘积低于 1.0。在大多数处理器上,这种方法意味着将舍入模式更改 3 次,并且每次更改都代价高昂(涉及刷新 CPU 管道)。

使用 FMA 指令,可以计算 fma(a, b, -1.0) 并将结果与​​ 0.0 进行比较。由于浮点数在零附近更密集,并且由于计算中没有四舍五入中间乘积,我们可以确定fma(a, b, -1.0) > 0 表示ab 的数学乘积大于1,以此类推.

示例:Veltkamp/Dekker 乘法

double-double 格式将数字有效地表示为两个双精度浮点数之和。它几乎与四精度一样精确,但利用了现有的双精度硬件。

考虑以下函数Mul12(a, b),它接受两个双精度数ab,并将它们的乘积计算为双双数。 Veltkamp 和 Dekker 的算法仅使用双精度加法和乘法来计算此函数 (reference)。它需要 6 次乘法(每个 Split() 的一部分加上算法主体中的 4 次),以及大量的加法。

如果 FMA 指令可用,Mul12 可以实现为两个操作,一个乘法和一个 FMA。

high = a * b; /* double-precision approximation of the real product */
low = fma(a, b, -high); /* remainder of the real product */
/* now the real product of a and b is available as the sum of high and low */

更多示例

FMA 用于计算精度的示例,不仅作为执行乘法和加法的指令,还包括计算平方根和除法。这些运算必须根据 IEEE 754 标准正确舍入(到数学结果的最接近的浮点数)。当有硬件 FMA 指令可用时,这两个操作可以有效地实现。这方面通常被编译链隐藏,但 IA-64 指令集 (Itanium) 没有除法指令。相反,可以通过涉及 FMA 的一系列指令(通常由编译器生成)来获得正确的舍入除法。

【讨论】:

  • @Zboson 谢谢,我已将参考替换为另一个快速扫描后的参考。
  • 直到您的回答,我才真正了解 FMA 的优点。 FMA 带来的性能优势并没有我预期的那么大。但这是因为我对额外的精度不感兴趣。在需要额外精度的情况下,例如在实现 double-double 时,我可以看到它非常有帮助。谢谢!
  • this 你可能会感兴趣。
  • 在你的第二个例子中,为什么不能简单地返回 fma(a, b, 0)?
  • @Royce 因为融合乘加的最终结果是一个双精度浮点数。只有中间结果具有(实际上)无限精度(注意:“实际上”,因为在实践中,由于已知此中间结果仅打算添加到双精度以返回双精度,因此并非所有位都可以在同时在处理器中)。如果您计算 fma(a, b, 0),您将得到最接近数学乘积 a*b 的双精度数(与计算 a*b 相同)。要查看后面的数字,请使用 fma(a, b, -a*b) 取消第一个数字。
【解决方案2】:

它通常用作优化。大多数浮点单元都有一条fma 指令,因此可以在一条指令中执行计算,而不是两条或更多条指令。所以对于性能关键的浮点代码来说,这是一个很有帮助的函数。

【讨论】:

  • “一条指令而不是两条”方面是 FMA 中最不重要的。 FMA 指令所占用的周期数(如果存在)不必小于乘法和加法所占用的周期数。它至少和乘法一样昂贵,加法可以忽略不计,可能会或可能不会免费加入。我会写一个答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-11
  • 2013-09-17
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多