为了账号安全,请及时绑定邮箱和手机立即绑定

找出两个 1d 数组之间的差异,以在最短的时间内形成这些差异的 2d 数组

找出两个 1d 数组之间的差异,以在最短的时间内形成这些差异的 2d 数组

C#
犯罪嫌疑人X 2022-07-23 17:27:52
我试图找到一个数组的每个元素与另一个数组的每个元素之间的绝对差异以形成一个矩阵。我已经使用 for 循环实现了这一点,但它很慢,我需要它更快。例如,我可以通过使用 dist 方法在 R 中更快地做到这一点,但我正在努力在 C# 中让它变得更快。double[] array1 = new double [] { 1.1, 2.0, 3.0, 4.0, 5.0 };double[] array2 = new double[] { 6.1, 7.0, 8.0};    double[,] final_array = new double[5, 3];for (int i = 0; i < 5; i++){    for (j = 0; j < 3; j++)    {        final_array[i,j] = Math.Abs(array1[i] - array2[j])    }}# expected result of final_array5    4.1    3.1     2.1     1.15.9  5      4       3       26.9  6      5       4       3虽然这个结果是正确的答案,但我想更快地做到这一点,因为我需要对最大为 15,000 的数组进行此计算。
查看完整描述

2 回答

?
幕布斯7119047

TA贡献1794条经验 获得超8个赞

您可以在命名空间中使用向量System.Numerics。需要注意的是,它只适用于float,而不适用于double。不过,这不应该是减法的问题:


float[] array1 = new float[] { 1.1F, 2.0F, 3.0F, 4.0F, 5.0F };

float[] array2 = new float[] { 6.1F, 7.0F, 8.0F };    

float[,] final_array = new float[array1.Length, array2.Length];


int vectorCount = array2.Length / 4;

Vector4[] array2Vectors = new Vector4[vectorCount];

Parallel.For(0, vectorCount, i =>

{

    int offset = i * 4;

    array2Vectors[i] = new Vector4(array2[offset], array2[offset + 1],

        array2[offset + 2], array2[offset + 3]);

});


Parallel.For(0, array1.Length, i =>

{

    Vector4 v1 = new Vector4(array1[i], array1[i], array1[i], array1[i]);

    for (int j = 0; j < array2Vectors.Length; j++)

    {

        Vector4 result = Vector4.Abs(Vector4.Subtract(v1, array2Vectors[j]));

        int offset = j * 4;

        final_array[i, offset] = result.X;

        final_array[i, offset + 1] = result.Y;

        final_array[i, offset + 2] = result.Z;

        final_array[i, offset + 3] = result.W;

    }


    for (int j = vectorCount * 4; j < array2.Length; j++)

    {

        final_array[i,j] = Math.Abs(array1[i] - array2[j]);

    }

});

由于您现在使用向量,因此您将使用 CPU 的 SIMD 指令,这将加快您的任务。


额外的性能提升来自Parallel.For使用所有可用 CPU 内核的并行执行。


查看完整回答
反对 回复 2022-07-23
?
PIPIONE

TA贡献1829条经验 获得超9个赞

就算法复杂性而言,没有办法更快地做到这一点。它需要精确O(n * m)的操作来计算这个结果,至少因为你有那个大小的结果数组。


有一些方法可以稍微提高代码本身的性能。

正如评论中已经建议的那样,最简单的一种是切换到锯齿状数组:


double[] array1 = new double [] { 1.1, 2.0, 3.0, 4.0, 5.0 };

double[] array2 = new double[] { 6.1, 7.0, 8.0};    

double[][] final_array = new double[5][];


for (int i = 0; i < 5; i++)

{

    final_array[i] = new double[3];

    for (int j = 0; j < 3; j++)

    {

        final_array[i][j] = Math.Abs(array1[i] - array2[j]);

    }

}

您可以在此处阅读有关多维数组与交错数组及其性能的更多信息:

C# 中多维数组和数组数组之间的区别是什么?


您还可以通过使用不安全指针访问多维数组或利用高级处理器指令(内在函数)进一步提高性能,但是......问题是:这真的是您需要考虑的事情吗?它是极高负载系统中唯一的瓶颈吗?如果不是,那么只需将您的代码保持原样,以清晰易读和易于理解的形式。说到性能,O(n * m)渐近复杂度对于大小为 15000 的数组来说非常好。


查看完整回答
反对 回复 2022-07-23
  • 2 回答
  • 0 关注
  • 92 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信