Поворот 2D точек с помощью System.Numerics.Vectors - PullRequest
0 голосов
/ 18 октября 2018

Я стремлюсь оптимизировать программу, в основе которой лежит множество расчетов, основанных на ротации множества 2D-точек.Я искал вокруг, чтобы увидеть, возможно ли сделать эти вычисления, используя SIMD в C #.

Я нашел ответ на c ++, который, кажется, делает то, что я хочу, но я не могу перевести это на C # с помощью пакета System.Numerics.Vectors.

Оптимизация 2D-вращения

Может ли кто-нибудь указать мне правильное направление, как это можно сделать?

В приведенном ниже коде показан обычный метод без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;
    }

Edit: Мне удалось получить реализацию, работающую с использованием двух 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 голосов
/ 19 октября 2018

Код, добавленный в редактировании, является хорошим началом, однако код для 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;
    }
}
...