SSE等矢量编程(SIMD)

Las*_*eak 2 c x86 sse simd

我对 SSE 编程完全陌生,但拥有 Intel Core i7 处理器。

基本上,我想一次取 4 个 32 位无符号整数并将它们全部立方(求 3 次方)。据我了解,SSE 及其后续产品的 SIMD 功能使这成为可能,但我到底该如何去做呢?最好用 C 语言,但如果需要的话我可以管理汇编。

编辑以明确我的最终目标:

然后,我想将所有立方体加在一起得出一个数字。

背景:我只是想使用 SSE 来优化确定一个数字是否是阿姆斯特朗数字(一个三位数,其每个数字的立方之和与数字本身相同)。一个例子是153。除了暴力之外似乎没有其他办法可以做到这一点。这些是自恋数字的子集,其所有数字的总和乘以十进制数字的长度次方等于数字本身。希望我最终能将其扩展得更加灵活,一开始我只是做阿姆斯特朗的数字。正如您可能想象的那样,这个问题出现在另一个网站上,我们中的一些人正在尝试对其进行优化。通过采纳你的想法和我自己的研究,我想出了这个代码:

#include <stdio.h>
#include <smmintrin.h>  // SSE 4.1

__m128i vcube(const __m128i v)
{
    return _mm_mullo_epi32(v, _mm_mullo_epi32(v, v));
}


int main(int argc, const char * argv[]) {
    for (unsigned int i = 1; i <= 500; i++) {
        unsigned int firstDigit = i / 100;
        unsigned int secondDigit = (i - firstDigit * 100) / 10;
        unsigned int thirdDigit = (i - firstDigit * 100 - secondDigit * 10);

        __m128i v = _mm_setr_epi32(0, firstDigit, secondDigit, thirdDigit);
        __m128 v3 = (__m128) vcube(v);

        v3 = _mm_hadd_ps(v3, v3);
        v3 = _mm_hadd_ps(v3, v3);

        if (_mm_extract_epi32((__m128i) v3, 0) == i)    
            printf ("%03d is an Armstrong number\n", i);
        }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

注意:我必须进行一些类型强制才能使其在某些系统(Solaris,至少某些 Linux)中进行编译。

所以这可行,但也许可以简化。抱歉,我没有发布整个任务,但我试图将其分解为步骤,并且我想确保每个数字的立方正确。

(编辑结束)

谢谢你!

编辑:我想我应该添加我正在运行 Mac OS X Sierra。

再次编辑:

那么,假设我制作了所有这些无符号短整型而不是无符号整数,并添加了更多数字,当短整型可能无法容纳所有数字的总和时,如何将它们加在一起?如果您知道我的意思,有没有办法将它们添加并存储在较大变量的向量中,或者存储在更大的数字(例如 UInt64)中?

对于所有问题,我深表歉意,但正如我所说,尽管我从第一台 Mac G4 开始就接触过矢量处理,但我对矢量处理还是完全陌生的。

Pau*_*l R 5

如果您的输入值在 0..1625 范围内(以便结果适合 32 位),那么您可以使用_mm_mullo_epi32

__m128i vcube(const __m128i v)
{
    return _mm_mullo_epi32(v, _mm_mullo_epi32(v, v));
}
Run Code Online (Sandbox Code Playgroud)

演示:

#include <stdio.h>
#include <smmintrin.h>  // SSE 4.1

__m128i vcube(const __m128i v)
{
    return _mm_mullo_epi32(v, _mm_mullo_epi32(v, v));
}

int main()
{
    __m128i v = _mm_setr_epi32(0, 1, 1000, 1625);
    __m128i v3 = vcube(v);

    printf("%vlu => %vlu\n", v, v3);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译并测试:

$ gcc -Wall -Wno-format-invalid-specifier -Wno-format-extra-args -msse4 vcube.c && ./a.out
0 1 1000 1625 => 0 1 1000000000 4291015625
Run Code Online (Sandbox Code Playgroud)