是否存在可以使用libc中的函数fma的情况?

时间:2012-11-08 15:24:43

标签: c floating-point posix libc fma

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

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

值为无限精度,并对结果格式进行一次

然而,AFAICT我以前从未见过这样的三元手术。所以我想知道这个功能的用途是什么。

2 个答案:

答案 0 :(得分:16)

融合乘法 - 加法指令的重要方面是中间结果的(虚拟)无限精度。这有助于提高性能,但不是因为两个操作在一条指令中编码 - 它有助于提高性能,因为中间结果的几乎无限精度有时很重要,并且非常昂贵当这个精度水平真正是程序员所追求的时候,乘法和加法。

示例:将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。在大多数处理器上,这种方法意味着更改舍入模式三次,每次更改都很昂贵(它涉及刷新CPU管道)。

  3. 使用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()的一部分加上算法主体中的四个),还有很多补充。

    如果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指令,因此可以在单个指令中执行计算,而不是两个或更多。因此,对于性能关键的浮点代码,它是一个有用的函数。