C 按行与按列访问矩阵元素

C 按行与按列访问矩阵元素,c,arrays,C,Arrays,给出了一个矩阵A[i][j]。如果我们想添加矩阵的元素,哪种方法更好?为什么 列式 按行 在我看来,行方式更好,因为数组中的表示元素存储在连续的内存位置,所以访问它们所需的时间更少。但是,由于在RAM中,获取每个位置所需的时间相等,这有关系吗?利用 在C中,矩阵存储在r中。因此,如果您访问元素a[i][j],那么对元素a[i][j+1]的访问很可能会命中缓存。不执行对主存储器的访问。缓存比主内存快,所以访问模式很重要 当然,还必须考虑更多因素,如写访问/读访问、写策略(直写、写回/写分配、无写分

给出了一个矩阵
A[i][j]
。如果我们想添加矩阵的元素,哪种方法更好?为什么

  • 列式
  • 按行

  • 在我看来,行方式更好,因为数组中的表示元素存储在连续的内存位置,所以访问它们所需的时间更少。但是,由于在RAM中,获取每个位置所需的时间相等,这有关系吗?

    利用

    在C中,矩阵存储在r中。因此,如果您访问元素
    a[i][j]
    ,那么对元素
    a[i][j+1]
    的访问很可能会命中缓存。不执行对主存储器的访问。缓存比主内存快,所以访问模式很重要

    当然,还必须考虑更多因素,如写访问/读访问、写策略(直写、写回/写分配、无写分配)、多级缓存等。但对于这个问题来说,这似乎是矫枉过正

    使用分析工具(例如)享受一些乐趣,并亲自查看

    例如,考虑一个可以访问4MB矩阵的虚拟程序。检查每个访问模式的未命中率之间的差异

    列访问

    $ cat col_major.c 
    #include <stdio.h>
    
    int main(){
    
        size_t i,j;
    
        const size_t dim = 1024 ;
    
        int matrix [dim][dim];
    
        for (i=0;i< dim; i++){
            for (j=0;j <dim;j++){
                matrix[j][i]= i*j;
            }
        }
        return 0;
    }
    
    $ valgrind --tool=cachegrind ./col_major 
    
    ==3228== D   refs:      10,548,665  (9,482,149 rd   + 1,066,516 wr)
    ==3228== D1  misses:     1,049,704  (      968 rd   + 1,048,736 wr)
    ==3228== L2d misses:     1,049,623  (      893 rd   + 1,048,730 wr)
    ==3228== D1  miss rate:        9.9% (      0.0%     +      98.3%  )
    ==3228== L2d miss rate:        9.9% (      0.0%     +      98.3%  )
    
    $ cat row_major.c 
    #include <stdio.h>
    
    int main(){
        size_t i,j;
        const size_t dim = 1024 ;
        int matrix [dim][dim];
    
        for (i=0;i< dim; i++)
            for (j=0;j <dim;j++)
                matrix[i][j]= i*j;
    
        return 0;
    }
    
    $ valgrind --tool=cachegrind ./row_major 
    
    ==3524== D   refs:      10,548,665  (9,482,149 rd   + 1,066,516 wr)
    ==3524== D1  misses:        66,664  (      968 rd   +    65,696 wr)
    ==3524== L2d misses:        66,583  (      893 rd   +    65,690 wr)
    ==3524== D1  miss rate:        0.6% (      0.0%     +       6.1%  )
    ==3524== L2d miss rate:        0.6% (      0.0%     +       6.1%  )
    
    $cat col_major.c
    #包括
    int main(){
    尺寸i,j;
    常量大小\u t dim=1024;
    整数矩阵[dim][dim];
    对于(i=0;i对于(j=0;j如果阵列很小,这并不重要。如果阵列很大,则读取时间可能会受到影响。最大的问题是缓存。如果不能期望将完整的矩阵立即加载到缓存中,则希望将遇到的缓存未命中数目降至最低,因为处理缓存未命中相对耗时。


    如果数组真的很大,那么您可能会因为页面交换次数过多而受到更大的性能影响。

    对于C,处理多维数组的最佳方法是:

    int a[MAX_I][MAX_J];
    for (i = 0; i < MAX_I; ++i) {
       for (j = 0; j < MAX_J; ++j) {
          /* process a[i][j] */
       }
    }
    
    inta[MAX_I][MAX_J];
    对于(i=0;i

    这是因为C语言将数组作为带偏移量的指针来处理,请参见:。

    您使用的是什么语言?不同的语言对矩阵有不同的表示,这会影响它们的使用方式。请问您是否打算编写
    I
    j@Tom来存储矩阵column major,你应该按列的主要顺序迭代它们,对吗?这会纠正我猜的缓存未命中,还是我遗漏了什么?这个问题被标记为C,C以行的主要顺序存储多维数组。如果你使用的是其他语言,可以按列的主要顺序,那么是的,一次完成一列的所有操作会比一次做所有的一排。