C 如何使用SSE汇编指令查找毕达哥拉斯三元组?
我对汇编非常陌生,我想找到所有毕达哥拉斯三元组,范围从1到100。我用C生成所有的数字,所有其他的计算都应该用汇编语言完成。我试图通过使用sqrt命令来实现这一点(我已经尝试了所有这些命令),但我无法使其工作。。 有人能告诉我应该怎么做吗 这就是我到目前为止得到的:C 如何使用SSE汇编指令查找毕达哥拉斯三元组?,c,assembly,sse,C,Assembly,Sse,我对汇编非常陌生,我想找到所有毕达哥拉斯三元组,范围从1到100。我用C生成所有的数字,所有其他的计算都应该用汇编语言完成。我试图通过使用sqrt命令来实现这一点(我已经尝试了所有这些命令),但我无法使其工作。。 有人能告诉我应该怎么做吗 这就是我到目前为止得到的: int main(){ for (int i = 1; i <= 100; i++) { a++; if (a &
int main(){
for (int i = 1; i <= 100; i++)
{
a++;
if (a > 100)
a = 0;
for (int j = 1; j <= 100; j++)
{
b++;
if (b > 100)
b = a;
_asm //tricky part begins here:
{
movups xmm0, a
movups xmm1, b
pmuludq xmm0, xmm0
pmuludq xmm1, xmm1
//movups xmm2, 0
//paddd xmm2, xmm0
//paddd xmm2, xmm1
movups z, xmm0
}
printf("%d\n", z);
}
}
}
intmain(){
对于(int i=1;i 100)
a=0;
对于(int j=1;j 100)
b=a;
_asm//棘手的部分从这里开始:
{
movups xmm0,a
movups xmm1,b
pmuludq xmm0,xmm0
pmuludq xmm1,xmm1
//movups xmm2,0
//paddxmm2,xmm0
//paddxmm2,xmm1
movz,xmm0
}
printf(“%d\n”,z);
}
}
}
您的方法的基本问题是,您需要并行查看4个b
值,因此不能仅从C标量变量加载。您需要在循环迭代中保持向量寄存器中的内容,因为您不仅仅是从内存或其他地方加载向量。您应该在asm中编写整个循环,因为MSVC内联asm不适合包装短序列,这是因为获取结果的开销不可避免
当然,将此循环矢量化的最佳方法是使用C intrinsic,而不是使用内联asm。然后,如果有必要(如果可能的话),您可以通过检查编译器的asm输出的低效性来帮助编译器生成更好的asm。(见附件)
当然,如果您真的只是想创建高效的代码来生成毕达哥拉斯三元组,那么您的算法也是假的: 维基百科的文章有一节描述了欧几里德的公式。迭代这将是一个不同于在整个
a=[1..100]b=[1..100]
搜索空间的暴力搜索中检查命中率的问题,因为检查一个数字是否是一个完美的正方形相当慢
此外,检测与条件匹配的向量元素也很笨拙。压缩比较指令和PMOVMSKB(或MOVMSKPS)将为您提供位图,但这在命中次数很少时最有效,例如,在第一次命中后循环停止的位置实现
memchr
。“我想在汇编中执行此操作,因为我知道它比C快。”您怎么知道?因为它可能不会。我不会假设您手工编写的asm将比C编译器的输出更快。编译器是智能的,现代CPU是复杂的。我以为所有的形式都是n*(a*a=b+c)
之类的?一些数学运算应该比C和汇编更快。如果你想学习asm,可以在asm中编写整个循环(或者更好,编写整个函数)。以这种方式使用MSVC内联asm只会让你自食其果。请参阅,这也解释了为什么MSVC内联asm在这方面很糟糕。@Blorgbeard和Rukass:几乎总是可以用手写asm打败编译器,但你必须知道自己在做什么。通常最好从优化的编译器输出开始,这样至少不会做得更糟。但是通常最好的办法是在你找到了什么是最优的之后,调整你的C源代码,使编译器能够生成更好的asm。请参阅my了解更多信息。请注意,在台式计算机上检查整个a=[1..100]b=[1..100]
搜索空间的时间平均不到.005秒,因此这个问题的整个前提是荒谬的。@user3386109:这仍然是一百万或两个核心时钟周期,足够长,可以用性能计数器精确测量。但显然,这一点更适用于更大的搜索范围。在每次搜索命中的时候调用<代码> PROTFF <代码>是荒谬的,而不是把它们存储在一个数组中。