5

我看到这个页面,发现有一个奇怪的浮动乘法相加 函数——fmafmaf。它说结果是这样的:

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

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

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

4

2 回答 2

17

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

示例:a * b比较1.0

假设确定两个双精度数的乘积ab非零常数(我们将使用1.0)的位置对算法至关重要。数字ab都具有二进制数字的完整有效位。如果您计算a*b为 a 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的数学乘积大于 1,依此类推。ab

示例:Veltkamp/Dekker 乘法

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

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

如果有 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 的一系列指令(通常由编译器生成)来获得正确舍入的除法。

于 2013-08-14T18:44:22.957 回答
2

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

于 2012-11-08T15:27:29.427 回答