是时候进入位数组数组了

Posted

技术标签:

【中文标题】是时候进入位数组数组了【英文标题】:time to get in array of bitarrays 【发布时间】:2019-02-05 06:30:45 【问题描述】:

我在那个代码中有一个我不明白的问题:

ilProbekUcz= valuesUcz.Count; //valuesUcz is the list of <float[]>
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)

        int index = 0;
       linia = (float[])valuesUcz[i];//removing this line not solve problem
        for (int a = 0; a < ileRazem; a++)
                for (int b = 0; b < ileRazem; b++)
                        if (a != b)
                        
                                bool value = linia[a] >= linia[b];
                                nodesValueArrayUcz[index][i] = value;
                                nodesValueArrayUcz[ilWezlowDanychP2 + index][i] = !value;
                                index++;
                        

sw.Stop();

当我将 valuesUcz 的大小增加 2 倍时,执行时间会增加 4 倍

当我将 valuesUcz 的大小增加 4 倍时,执行时间增加了 8 倍 等等……

ileRazem,ilWezlowDanych同理)

我明白:ilProbekUcz 的增加会增加BitArrays 的大小,但我对其进行了多次测试,这没问题 - 时间应该线性增长 - 在代码中:

ilProbekUcz= valuesUcz.Count; //valuesTest is the list of float[]
for (int i = 0; i < ilWezlowDanych; i++) nodesValueArrayUcz[i] = new BitArray(ilProbekUcz);
BitArray test1 = nodesValueArrayUcz[10];
BitArray test2 = nodesValueArrayUcz[20];
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < ilProbekUcz; i++)

        int index = 0;
       linia = (float[])valuesUcz[i];//removing this line not solve problem
        for (int a = 0; a < ileRazem; a++)
                for (int b = 0; b < ileRazem; b++)
                        if (a != b)
                        
                                bool value = linia[a] >= linia[b];
                                test1[i] = value;
                                test2[i] = !value;
                                index++;
                        

时间线性增长,所以问题是从数组中取一个BitArray...

有什么方法可以更快吗? (我希望时间线性增长)

【问题讨论】:

...时间线性增长,所以问题是从数组中取出一个BitArray...有什么方法可以更快地做到这一点吗? (我希望时间增长线性 ... O(1 * n) = O(2 * n) = ... = O(c * n) = O(n ),其中 c 是一个常数。 什么是ileRazem linia 的大小 - 我在 1440、2880、5760 处测量时间 但是“linia”不是问题,我把它变成了一个常数,时间都是一样的 您可以删除linia 并使用bool value = valuesUcz[ i ][ a ] &gt;= valuesUcz[ i ][ b ];。你说没用。如果你不告诉你想要完成什么,我们无法帮助你。我们只能看到 3 个for 循环在做某事。 【参考方案1】:

您必须了解,测量时间有很多因素导致它们不准确。在您的示例中拥有 huuuuuge 数组时,最大的因素是 cashe misses。考虑到 cshe 时,写同样的东西很多次,可能会快 2-5 倍或更多倍。两个词 Cashe 的工作原理,非常粗略。缓存是cpu内部的内存。它比 ram 快 waaaaaaaaaaaaaay,所以当你想从内存中获取一个变量时,你要确保这个变量存储在缓存中而不是 ram 中。如果它存储在缓存中,我们说我们有一个hit,否则是一个miss。有时,不是经常,一个程序太大以至于它将变量存储在硬盘驱动器中。在这种情况下,当您获取这些时,您会延迟击中 huuuuuuuuuuuge!缓存示例:

假设我们在内存(ram)中有一个包含 10 个元素的数组

当你得到第一个元素 testArray[0] 时,因为 testArray[0] 不在缓存中,cpu 会将这个值 一起带上一个数字(比如说 3,数量取决于数组的相邻元素的 cpu) 例如它存储到缓存 testArray[0], testArray[1], testArray[2], testArray[3]

现在当我们得到testArray[1] 时,它在缓存中,所以我们有一个hittestArray[2]testArray[3] 也是如此。 testArray[4] 不在缓存中,所以它会得到 testArray[4] 以及另外 3 个 testArray[5], testArray[6], testArray[7]

等等…… 缓存misses 非常昂贵。这意味着您可能期望双倍大小的数组可以访问两倍的时间。但是这是错误的。更大的数组更多misses 并且时间可能会比您预期的时间增加 2 倍或 3 倍或 4 倍或更多倍。这个是正常的。在您的示例中,这就是正在发生的事情。从 1 亿个元素(第一个数组)到 4 亿个(第二个数组)。 misses不是双倍的,而是你看到的更多。一个非常酷的技巧与访问数组的方式有关。在您的示例中,ba1[j][i] = (j % 2) == 0;ba1[i][j] = (j % 2) == 0; 差得多。 ba2[j][i] = (j % 2) == 0;ba1[i][j] = (j % 2) == 0; 也是如此。你可以测试一下。只需反转i and j。它与二维数组在内存中的存储方式有关,因此在第二种情况下,hits 比第一种情况多。

【讨论】:

谢谢,我知道 ba[i][j] 更快 - 它的时间会线性增长;),算法需要从第一个代码开始按顺序填充它们......我需要考虑一下它 - 但我有一个问题:你知道一些方法让我影响缓存中的内容吗? @barpas 你不能。只要数据是连续的,一个接一个,CPU就会自动执行。在您的循环中,有 99,9999% 的时间浪费在获取缓存值上。因此,如果这些值不是彼此相邻的,那么您就有很大的问题。您必须了解array[0][0]array[1][0] 在内存中在一起。但是array[0][0]array[0][1] 是!告诉我你的算法是做什么的,这样我就可以在你的代码中帮助你。 如您所见,有行数组,有值 - 它比较 linie (float[]) 中的每个值并将结果放入适当的位数组,行按时间排序,位数组按时间排序比较值 bitarray 中的每一位是下一个时间段 @barpas 我需要确切的代码,否则我帮不了你

以上是关于是时候进入位数组数组了的主要内容,如果未能解决你的问题,请参考以下文章

两组有序数列的中位数

Javascript 数组自定义排序,并获取排序后的保存原索引的同位数组(堆排序实现)

分组数据怎么求中位数

如何展平钳位数组

C#编程(维数组)----------位数组

Icarus Verilog:多位数组解析错误