我对 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 开始就接触过矢量处理,但我对矢量处理还是完全陌生的。
如果您的输入值在 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)