有没有可以使用libc中的函数fma的情况?

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

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

并且值是无限精度并且对结果格式进行一次舍入

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

融合乘加指令的重要方面是中间结果的(虚拟)无限精度。 这有助于提高性能,但不是因为两个操作在单个指令中编码 – 它有助于提高性能,因为中间结果的几乎无限精度有时很重要,而且当使用普通乘法和加法时,恢复非常昂贵精确度正是程序员追求的目标。

示例:将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管道)。

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

示例:Veltkamp / Dekker乘法

双倍格式是数字的有效表示,是两个双精度浮点数的总和。 它几乎与四精度一样精确,但利用现有的双精度硬件。

考虑以下函数, Mul12(a, b) ,它采用两个双精度数字ab并将它们的乘积计算为双重数字。 由于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的一系列指令(通常由编译器生成)来获得正确舍入的除法。

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