如何将两个 64 位整数乘以另外 2 个 64 位整数?
我没有找到任何可以做到这一点的说明。
最佳答案
迟到的答案,但这是巴拉巴斯发布的更好版本。
如果您曾经使用过 GCC 或 Clang 的向量扩展,这就是他们使用的例程。
这使用与长乘法和网格乘法相同的方法。
65
* 73
----
15 // (5 * 3)
180 // (6 * 3) * 10
350 // (5 * 7) * 10
+ 4200 // + (6 * 7) * 100
------
4745
然而,它不是以 10 为单位,而是以 32 位为单位,并省略最后一个乘法,因为它总是会移过第 64 位,就像如果你不乘 6*7 一样截断大于 99 的值。
#include <emmintrin.h>
/*
* Grid/long multiply two 64-bit SSE lanes.
* Works for both signed and unsigned.
* ----------------.--------------.----------------.
* | | b >> 32 | a & 0xFFFFFFFF |
* |----------------|--------------|----------------|
* | d >> 32 | b*d << 64 | a*d << 32 |
* |----------------|--------------|----------------|
* | c & 0xFFFFFFFF | b*c << 32 | a*c |
* '----------------'--------------'----------------'
* Add all of them together to get the product.
*
* Because we truncate the value to 64 bits, b*d << 64 will be zero,
* so we can leave it out.
*
* We also can add a*d and b*c first and then shift because of the
* distributive property: (a << 32) + (b << 32) == (a + b) << 32.
*/
__m128i Multiply64Bit(__m128i ab, __m128i cd)
{
/* ac = (ab & 0xFFFFFFFF) * (cd & 0xFFFFFFFF); */
__m128i ac = _mm_mul_epu32(ab, cd);
/* b = ab >> 32; */
__m128i b = _mm_srli_epi64(ab, 32);
/* bc = b * (cd & 0xFFFFFFFF); */
__m128i bc = _mm_mul_epu32(b, cd);
/* d = cd >> 32; */
__m128i d = _mm_srli_epi64(cd, 32);
/* ad = (ab & 0xFFFFFFFF) * d; */
__m128i ad = _mm_mul_epu32(ab, d);
/* high = bc + ad; */
__m128i high = _mm_add_epi64(bc, ad);
/* high <<= 32; */
high = _mm_slli_epi64(high, 32);
/* return ac + high; */
return _mm_add_epi64(high, ac);
}
Compiler Explorer注意:下面还包含 GCC 矢量扩展版本以供比较。
关于x86 - 2 个 64 位整数的 SSE 乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17863411/