我遇到this page并发现有一个奇怪的浮动乘法添加函数 - fma
和fmaf
。它说结果是这样的:
(x * y) + z #fma(x,y,z)
值为无限精度,并对结果格式进行一次。
然而,AFAICT我以前从未见过这样的三元手术。所以我想知道这个功能的用途是什么。
答案 0 :(得分:16)
融合乘法 - 加法指令的重要方面是中间结果的(虚拟)无限精度。这有助于提高性能,但不是因为两个操作在一条指令中编码 - 它有助于提高性能,因为中间结果的几乎无限精度有时很重要,并且非常昂贵当这个精度水平真正是程序员所追求的时候,乘法和加法。
a * b
与1.0
假设算法确定两个双精度数a
和b
的乘积相对于非零常数的位置至关重要(我们将使用1.0
)。数字a
和b
都具有二进制数字的完整有效数字。如果您将a*b
计算为double
,则结果可能是1.0
,但这并不能告诉您实际数学产品是否略低于1.0并且向上舍入到恰好为1.0或稍微高于1.0并向下舍入。没有FMA,您的选择是:
将a*b
计算为四精度数。四精度没有在硬件中实现,但有软件仿真库。在四精度中,产品的数学结果是完全可表示的,然后您可以将其与1.0进行比较。
在向上舍入模式和向下向下模式下以双精度计算a*b
。如果两个结果均为1.0,则表示a*b
正好为1.0。如果RU(a * b)大于1.0,则表示数学乘积大于1.0,如果RD(a * b)小于1.0,则表示数学乘积小于1.0。在大多数处理器上,这种方法意味着更改舍入模式三次,每次更改都很昂贵(它涉及刷新CPU管道)。
使用FMA指令,可以计算fma(a, b, -1.0)
并将结果与0.0进行比较。由于浮点数在零附近更密集,并且由于中间乘积在计算中没有舍入,我们可以确定fma(a, b, -1.0) > 0
表示a
和b
的数学乘积更大比1,等等。
double-double格式是数字的有效表示,是两个双精度浮点数的总和。它几乎与四精度一样精确,但利用了现有的双精度硬件。
考虑以下函数Mul12(a, b)
,该函数采用两个双精度数a
和b
,并将其乘积计算为双倍数。由于Veltkamp和Dekker,算法仅使用双精度加法和乘法(reference)来计算此函数。它需要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的一系列指令(通常由编译器生成)来获得正确舍入的除法。
答案 1 :(得分:2)
它通常用作优化。大多数浮点单元都有fma
指令,因此可以在单个指令中执行计算,而不是两个或更多。因此,对于性能关键的浮点代码,它是一个有用的函数。