鉴于在二维空间中旋转的点的经典公式:优化二维旋转
cv::Point pt[NPOINTS];
cv::Point rotated[NPOINTS];
float angle = WHATEVER;
float cosine = cos(angle);
float sine = sin(angle);
for (int i = 0; i < NPOINTS; i++)
{
rotated[i].x = pt[i].x * cosine - pt[i].y * sine;
rotated[i].y = pt[i].x * sine + pt[i].y * cosine;
}
鉴于NPOINTS是32和阵列被对准,一个如何将着手优化SSE或AVX的代码?搜索在这里和其他地方不转了什么有用的,我迷路了关于这里:
__m128i onePoint = _mm_set_epi32(pt[i].x, pt[i].y, pt[i].x, pt[i].y);
__m128 onefPoint = _m128_cvtepi32_ps(onePoint);
__m128 sinCos = _mm_set_ps(cosine, -sine, sine, cosine);
__m128 rotated = _mm_mul_ps(onefPoint, sinCos);
但是如何去从[y*cosine, -x*sine, x*sine, y*cosine]
到[y*cosine + -x*sine, x*sine + y*cosine]
?这是最好的方法吗?它是否容易扩展到__m512
?
更新:我做了一些更多的研究,我现在有大约:
__m128i onePoint = _mm_set_epi32(pt[i].x, pt[i].y, pt[i].x, pt[i].y);
__m128 onefPoint = _m128_cvtepi32_ps(onePoint);
__m128i twoPoint = _mm_set_epi32(pt[i+1].x, pt[i+1].y, pt[i+1].x, pt[i+1].y);
__m128 twofPoint = _m128_cvtepi32_ps(twoPoint);
__m128 sinCos = _mm_set_ps(cosine, -sine, sine, cosine);
__m128 rotated1 = _mm_mul_ps(onefPoint, sinCos);
__m128 rotated2 = _mm_mul_ps(twofPoint, sinCos);
__m128 added = _mm_hadd_ps(rotated1, rotated2);
__m128i intResult = _mm_cvtps_epi32(added);
int results[4];
_mm_storeu_si128((__m128i*)results, intResult);
这使从处理器时间的11%一50%的增速约6%。扩展到__m256
并一次完成四个点可以提高速度。这看起来很糟糕的代码,但我正朝着正确的方向吗?
SIMD更好地“垂直”而不是“水平”地工作 - 尝试每次迭代处理4个点。 –
@PaulR是对的。如果同时处理4个点,不仅效率更高,而且代码的代数几乎与标量代码相同,即如何使用内在函数编写它将是显而易见的。 –
对于AVX,您应该同时处理8个点(4个与SSE)。 –