Tan*_*Man 1 c++ floating-point optimization arm neon
我正在尝试使用Neon内在函数为ARM A8处理器编写优化的点积,但我遇到了一些麻烦.首先,是否有任何库已经实现了这个?我的代码似乎有效,但在运行时会导致一些安静的失败 - 我最好的猜测是因为与未经优化的代码相比,精度略有下降.有没有更好的方法来完成我想要做的事情?我将非常感谢任何帮助或建议.提前致谢.
这个特殊的点积是一个32位浮点*32位浮点复数.
这是未经优化的代码:
double sum_re = 0.0;
double sum_im = 0.0;
for(int i=0; i<len; i++, src1++, src2++)
{
sum_re += *src1 * src2->re;
sum_im += *src1 * src2->im;
}
Run Code Online (Sandbox Code Playgroud)
这是我的优化版本:
float sum_re = 0.0;
float sum_im = 0.0;
float to_sum_re[4] = {0,0,0,0};
float to_sum_im[4] = {0,0,0,0};
float32x4_t tmp_sum_re, tmp_sum_im, source1;
float32x4x2_t source2;
tmp_sum_re = vld1q_f32(to_sum_re);
tmp_sum_im = vld1q_f32(to_sum_im);
int i = 0;
while (i < (len & ~3)) {
source1 = vld1q_f32(&src1[i]);
source2 = vld2q_f32((const float32_t*)&src2[i]);
tmp_sum_re = vmlaq_f32(tmp_sum_re, source1, source2.val[0]);
tmp_sum_im = vmlaq_f32(tmp_sum_im, source1, source2.val[1]);
i += 4;
}
if (len & ~3) {
vst1q_f32(to_sum_re, tmp_sum_re);
vst1q_f32(to_sum_im, tmp_sum_im);
sum_re += to_sum_re[0] + to_sum_re[1] + to_sum_re[2] + to_sum_re[3];
sum_im += to_sum_im[0] + to_sum_im[1] + to_sum_im[2] + to_sum_im[3];
}
while (i < len)
{
sum_re += src1[i] * src2[i].re;
sum_im += src1[i] * src2[i].im;
i++;
}
Run Code Online (Sandbox Code Playgroud)
如果您使用的是iOS,请在Accelerate框架中使用vDSP_zrdotpr.(vDSP_zrdotpr返回带有复矢量的实矢量的点积.还有其他变量,例如实数到实数或复数到复数.)
当然会失去精确度; 未经优化的代码会累积双精度和,而NEON代码会累积单精度和.
即使没有精确更改,结果也会有所不同,因为以不同顺序执行浮点运算会产生不同的舍入误差.(对于整数也是如此;如果计算7/3*5,则得到10,但5*7/3为11.)
存在用于进行具有减少的错误的浮点运算的算法.但是,对于高性能点阵产品,您通常会坚持使用所获得的产品.
一种选择是使用双精度NEON指令进行算术运算.当然,这不会像单精度NEON那么快,但它会比标量(非NEON)代码更快.