c# - 使用 System.Numerics.Vectors 旋转 2D 点

标签 c# simd

我正在寻求优化一个程序,该程序的大量计算基于大量 2D 点的旋转。我四处搜寻,看看是否可以在 C# 中使用 SIMD 进行这些计算。

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

Optimising 2D rotation

任何人都可以为我指明如何做到这一点的正确方向吗?

下面的代码显示了没有 SIMD 的常规方法。其中 Point 是一个具有 double 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< 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;

        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);
        }
    }

最佳答案

编辑中添加的代码是一个好的开始,但是 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;
    }
}

关于c# - 使用 System.Numerics.Vectors 旋转 2D 点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52882208/

相关文章:

c++ - 如何加快积分图像的计算?

c# 获取不规则对象边缘坐标的替代快速方法?

c# - 当 allow null 为真时,为什么默认值不插入列中?

当我使用 AVX 功能时崩溃

c - 移动 n 位的 __m128i

c - 如何使用缩放有效地将 16 位无符号短整型转换为 8 位无符号字符?

c++ - SQRT 对比 RSQRT 对比 SSE _mm_rsqrt_ps 基准

c# - 无法加载与 ADO.NET 提供程序对应的 SQL Server Compact 的 native 组件

c# - 从 Visual Studio 启动时,WPF 应用程序加载初始窗口的速度非常慢

c# - Aforge 内存使用