使用System.Numerics.Vectors旋转2D点

时间:2018-10-18 20:38:46

标签: c# simd

我正在寻找一个优化程序,该程序的很多计算都基于许多2D点的旋转。我到处搜索以查看是否有可能在C#中使用SIMD进行这些计算。

我在这里找到了一个c ++答案,似乎可以满足我的要求,但是我似乎无法使用System.Numerics.Vectors包将其转换为C#。

Optimising 2D rotation

有人能指出我正确的方向吗?

以下代码显示了不带SIMD的常规方法。 Point是具有X和Y两倍的结构。

    public static Point[] RotatePoints(Point[] points, double cosAngle, double sinAngle)
    {
        var pointsLength = points.Length;
        var results = new Point[pointsLength];

        for (var i = 0; i < pointsLength; i++)
        {
            results[i].X = (points[i].X * cosAngle) - (points[i].Y * sinAngle);
            results[i].Y = (points[i].X * sinAngle) + (points[i].Y * cosAngle);
        }

        return results;
    }

编辑: 我设法使用两个Vector 来实现一个实现,但是通过对它进行基准测试,这似乎比以前的实现要慢很多。

    private static void RotatePoints(float[] x, float[] y, float cosAngle, float sinAngle)
    {
        var chunkSize = Vector<float>.Count;
        var resultX = new float[x.Length];
        var resultY = new float[x.Length];

        Vector<float> vectorChunk1;
        Vector<float> vectorChunk2;

        for (var i = 0; i < x.Length; i += chunkSize)
        {
            vectorChunk1 = new Vector<float>(x, i);
            vectorChunk2 = new Vector<float>(y, i);

            Vector.Subtract(Vector.Multiply(vectorChunk1, cosAngle), Vector.Multiply(vectorChunk2, sinAngle)).CopyTo(resultX, i);
            Vector.Add(Vector.Multiply(vectorChunk1, sinAngle), Vector.Multiply(vectorChunk2, cosAngle)).CopyTo(resultY, i);
        }
    }

1 个答案:

答案 0 :(得分:2)

在编辑中添加的代码是一个好的开始,但是Vector.Multiply(Vector<float>, float)的代码生成非常糟糕,因此应避免使用此功能。避免这种情况很容易,只需在循环外部广播并乘以一个向量即可。我还添加了一个更合适的循环绑定和“标量结尾”,以防向量大小不能整齐地划分输入数组的大小。

private static void RotatePoints(float[] x, float[] y, float cosAngle, float sinAngle)
{
    var chunkSize = Vector<float>.Count;
    var resultX = new float[x.Length];
    var resultY = new float[x.Length];

    Vector<float> vectorChunk1;
    Vector<float> vectorChunk2;
    Vector<float> vcosAngle = new Vector<float>(cosAngle);
    Vector<float> vsinAngle = new Vector<float>(sinAngle);

    int i;
    for (i = 0; i + chunkSize - 1 < x.Length; i += chunkSize)
    {
        vectorChunk1 = new Vector<float>(x, i);
        vectorChunk2 = new Vector<float>(y, i);

        Vector.Subtract(Vector.Multiply(vectorChunk1, vcosAngle), Vector.Multiply(vectorChunk2, vsinAngle)).CopyTo(resultX, i);
        Vector.Add(Vector.Multiply(vectorChunk1, vsinAngle), Vector.Multiply(vectorChunk2, vcosAngle)).CopyTo(resultY, i);
    }
    for (; i < x.Length; i++)
    {
        resultX[i] = x[i] * cosAngle - y[i] * sinAngle;
        resultY[i] = x[i] * sinAngle + y[i] * cosAngle;
    }
}