Floating point 我可以使用AVX FMA单元进行位精确的52位整数乘法吗?

Floating point 我可以使用AVX FMA单元进行位精确的52位整数乘法吗?,floating-point,x86,simd,avx2,fma,Floating Point,X86,Simd,Avx2,Fma,AXV2没有任何源大于32位的整数乘法。它确实提供乘法,以及乘法1,但没有64位源 假设我需要一个输入大于32位,但小于或等于52位的无符号乘法-我可以简单地使用浮点或FMA指令吗?当整数输入和结果可以用52位或更少的位表示时(即在[0,2^52-1]范围内),输出是否精确 在更一般的情况下,我需要产品的所有104位,怎么样?或者整数乘积取52位以上的情况(即,乘积在位索引>52中具有非零值),但我只需要低52位?在后一种情况下,MUL将给我更高的位,并舍入一些较低的位(也许这就是IFMA的帮助

AXV2没有任何源大于32位的整数乘法。它确实提供乘法,以及乘法1,但没有64位源

假设我需要一个输入大于32位,但小于或等于52位的无符号乘法-我可以简单地使用浮点或FMA指令吗?当整数输入和结果可以用52位或更少的位表示时(即在[0,2^52-1]范围内),输出是否精确

在更一般的情况下,我需要产品的所有104位,怎么样?或者整数乘积取52位以上的情况(即,乘积在位索引>52中具有非零值),但我只需要低52位?在后一种情况下,
MUL
将给我更高的位,并舍入一些较低的位(也许这就是IFMA的帮助?)

编辑:事实上,也许它可以做任何事情,最多2^53,基于-我忘记了尾数之前隐含的前导
1
实际上给了你另一点


1有趣的是,64位product
PMULDQ
操作的延迟是32位
PMULLD
版本的一半,吞吐量是32位
PMULLD
版本的两倍,这在评论中是神秘的。

好吧,您当然可以对整数进行FP-lane操作。它们总是精确的:虽然有一些SSE指令不能保证正确的IEEE-754精度和舍入,但毫无例外,它们都是没有整数范围的指令,所以无论如何都不是您正在查看的指令。一句话:加法/减法/乘法在整数域中始终是精确的,即使是在压缩浮点上进行

至于四精度浮点(>52位尾数),不支持,而且在可预见的将来可能不会支持。只是对他们没有太多的要求。它们出现在一些SPARC时代的工作站架构中,但老实说,它们只是开发人员对如何编写数值稳定算法的不完全理解的包袱,随着时间的推移,它们逐渐消失


宽整数运算对于SSE来说是一个非常糟糕的选择。最近,当我实现一个大整数库时,我真的试图利用它,但老实说,它对我没有任何好处。x86是为多字运算而设计的;您可以在诸如ADC(产生并消耗进位)和IDIV(只要商不大于被除数,则允许除数的宽度为被除数的两倍)等操作中看到它,这一约束使得除数对于除多字除法以外的任何操作都没有用)。但多字算法本质上是顺序的,而SSE本质上是并行的。如果您足够幸运,您的数字刚好有足够的位放入FP尾数,恭喜您。但如果你有大整数,SSE可能不会是你的朋友。

是的,这是可能的。但对于AVX2,它不太可能比使用MULX/ADCX/ADOX的标量方法更好

对于不同的输入/输出域,这种方法几乎有无限的变化。我将只介绍其中的3个,但一旦你知道它们是如何工作的,它们就很容易推广

免责声明:

  • 这里的所有解决方案都假设舍入模式是舍入到偶数
  • 不建议使用快速数学优化标志,因为这些解决方案依赖于严格的IEEE

范围为[-251251]的有符号双精度

//A*B=L+H*2^52
//输入:A和B在[-2^51,2^51]范围内
//输出:L和H在[-2^51,2^51]范围内
已签署的无效文件(uuuM256D&L、uuuM256D&H、uuuM256D A、uuuM256D B){
常数m256d ROUND=_mm256_set1_pd(3042361440547750563592087692029024);/3*2^103
常数m256d刻度=_mm256_set1_pd(1./4503599627370496);/1/2^52
//乘法和加法归一化常数。这将强制乘法
//四舍五入到正确的位数。
H=_mm256_fmadd_pd(A、B、圆形);
//撤消规范化。
H=_mm256_sub_pd(H,圆形);
//回收产品的下半部分。
L=mm256 mmub pd(A,B,H);
//纠正H的缩放。
H=_mm256_mul_pd(H,刻度);
}
这是最简单的方法,也是唯一与标量方法竞争的方法。最终缩放是可选的,具体取决于您希望对输出执行的操作。因此,这只能被视为3个指令。但它也是最不有用的,因为输入和输出都是浮点值

两个FMA保持融合是绝对重要的。这就是快速数学优化可以打破的地方。如果第一个FMA被分解,则不再保证
L
[-2^51,2^51]
范围内。如果第二个FMA被分解,
L
将完全错误


范围为[-251251]的有符号整数

//A*B=L+H*2^52
//输入:A和B在[-2^51,2^51]范围内
//输出:L和H在[-2^51,2^51]范围内
已签署的无效文件(uuum256i&L,uuum256i&H,uuuum256i A,uuuuuuum256i B){
const uuum256d CONVERT_U=mm256_set1_pd(6755399441055744);/3*2^51
常数m256d转换=mm256设置1 pd(1.5);
__m256d l,h,a,b;
//转换为双精度
A=_mm256_add_epi64(A,_mm256_castpd_si256(CONVERT_));
B=_mm256_add_epi64(B,_mm256_castpd_si256(CONVERT_D));
a=_mm256_sub_pd(_mm256_castsi256_pd(a),CONVERT_);
b=_mm256_sub_pd(_mm256_castsi256_pd(b),CONVERT_D);
//获取上半部分。将H转换为int64。
h=_mm256_fmadd_pd(a,b,CONVERT_);
H=_mm256_sub_epi64(_mm256_castpd_si256(H),_mm256_castpd_si256(转换));
//撤消规范化。
h=_mm256_sub_pd(h,CONVERT_);
//恢复下半部分。
l=mm256 mmub pd(a,b,h);
//将L转换为int64
l=_mm256_add_pd(l,