乘积累加运算(英语:Multiply Accumulate, MAC)是在数字信号处理器或一些微处理器中的特殊运算。实现此运算操作的硬件电路单元,被称为“乘数累加器”。这种运算的操作,是将乘法的乘积结果和累加器 A 的值相加,再存入累加器。
若没有使用 MAC 指令,上述的程序可能需要二个指令,但 MAC 指令可以使用一个指令完成。而许多运算(例如卷积运算、点积运算、矩阵运算、数字滤波器运算、乃至多项式的求值运算)都可以分解为数个 MAC 指令,因此可以提高上述运算的效率。
简介MAC指令的输入及输出的数据类型可以是整数、定点数或是浮点数。若处理浮点数时,会有两次的数值修约(Rounding),这在很多典型的DSP上很常见。若一条MAC指令在处理浮点数时只有一次的数值修约,则这种指令称为“融合乘加运算”/“积和熔加运算”(fused multiply-add, FMA)或“熔合乘法累积运算”(fused multiply–accumulate, FMAC)。1
浮点运算中当使用整数时,操作通常是精确的(以2的幂为单位计算)。 但是浮点数只有一定的数学精度。 也就是说,数字浮点运算通常不是关联的或分布式的。 (请参阅浮点#精度问题。)因此,无论是使用两个舍入执行乘法加法,还是使用单个舍入(融合乘法加法)进行一次运算,结果都会产生差异。 IEEE 754-2008规定必须进行一次舍入,才能得到更准确的结果。
积和熔加运算融合乘加运算的操作和乘积累加的基本一样,对于浮点数的操作也是一条指令完成。但不同的是,非融合乘加的乘积累加运算,处理浮点数时,会先完成b×c的乘积,将其结果数值修约到N个比特,然后才将修约后的结果与寄存器a的数值相加,再把结果修约到N个比特;融合乘加则是先完成a+b×c的操作,获得最终的完整结果后方才修约到N个比特。由于减少了数值修约次数,这种操作可以提高运算结果的精度,以及提高运算效率和速率。
积和融加运算可以显著提升像是这些运算的性能和精度:
点积
矩阵乘法
多项式方程求解(像是秦九韶算法等)
牛顿法求解函数的零点
积和融加运算通常被依靠用来获取更精确的运算结果。然而,Kahan指出,如果不加思索地使用这种运算操作,在某些情况下可能会带来问题。像是平方差公式x−y,它等价于((x×x) −y×y),若果x与y已知数值,使用积和融加运算来求结果,哪怕x=y时,因为在进行首次乘法操作时无视低位的有效比特,可能会使运算结果出错,如果是多步运算,第一步就出错则会连累后续的运算结果接连出错,比如前述的平方差求值后,再取结果的平方根,那么这个结果也会出错。2
点积指令一些机器将多个融合乘法加法运算组合成单个步骤,例如, 在两个128位SIMD寄存器上执行四元素点积a0×b0 + a1×b1 + a2×b2 + a3×b3,具有单周期吞吐量。
支持FMA操作包含在IEEE 754-2008中。
DEC VAX的POLY指令用于使用一系列乘法和加法步骤来评估具有Horner规则的多项式。指令描述不指定是否使用单个fma步骤执行乘法和加法。[7]该指令自1977年原始的11/780实现以来一直是VAX指令集的一部分。
1999编程语言标准支持通过fma标准数学库函数进行FMA操作,以及基于FMA控制优化的标准编译指示。
融合的乘法-加法运算是在IBM POWER1(1990)处理器[8]中作为multiply-add融合引入的,但从那时起已被添加到众多其他处理器中:
HP PA-8000(1996)及以上版本
英特尔安腾(2001)
STI Cell(2006)
富士通SPARC64 VI(2007)及以上
(MIPS兼容)龙芯-2F(2008)
Elbrus-8SV(2018)
带有FMA3和/或FMA4指令集的x86处理器:
AMD Bulldozer(2011年,仅限FMA4)
AMD打桩机(2012,FMA3和FMA4)
AMD Steamroller(2014)
英特尔Haswell(2013年,仅限FMA3)
带VFPv4和/或NEONv2的ARM处理器:
ARM Cortex-M4F(2010)
ARM Cortex-A5(2012)
ARM Cortex-A7(2013)
ARM Cortex-A15(2012)
Qualcomm Krait(2012)
Apple A6(2012)
所有ARMv8处理器
GPU和GPGPU板:
Advanced Micro Devices GPU(2009)及更新版本
TeraScale 2“Evergreen”系列产品
NVidia GPU(2010)及更新版本
Maxwell-based(2014)
Pascal(2016)
Volta(2017)
英特尔MIC(2012)
ARM Mali T600系列(2012)及以上
应用到微处理器中的方法一种微处理器中的方法,用以预备执行一±A*B±C形式的融合乘积62相加运算,其通过发送第一与第二乘积62相加微指令至一或多个指令执行单元,以完成完整融合乘积62相加运算;第一乘积62相加微指令导引一未舍入非冗余结果向量、自(a)A与B的部分乘积、或(b)具有A与B部分乘积的C中的一选项的一第一相加运算产生;如果第一相加运算并未包括C,则第二乘积62相加微指令导引具有未舍入非冗余结果向量的C的一第二相加运算的执行,第二乘积62相加微指令亦导引、自未舍入非非冗余结果向量产生最终舍入结果,其中,最终舍入结果为融合乘积62相加运算的一完全结果。3
本词条内容贡献者为:
李宗秀 - 副教授 - 黑龙江财经学院