Row-major vs Column-major confusion

后端 未结 9 1407
离开以前
离开以前 2021-01-31 19:27

I\'ve been reading a lot about this, the more I read the more confused I get.

My understanding: In row-major rows are stored contiguously in memory, in column-major colu

相关标签:
9条回答
  • 2021-01-31 19:58

    Given the explanations above, here is a code snippet demonstrating the concept.

    //----------------------------------------------------------------------------------------
    // A generalized example of row-major, index/coordinate conversion for
    // one-/two-dimensional arrays.
    // ex: data[i] <-> data[r][c]
    //
    // Sandboxed at: http://swift.sandbox.bluemix.net/#/repl/5a077c462e4189674bea0810
    //
    // -eholley
    //----------------------------------------------------------------------------------------
    
    // Algorithm
    
    let numberOfRows    = 3
    let numberOfColumns = 5
    let numberOfIndexes = numberOfRows * numberOfColumns
    
    func index(row: Int, column: Int) -> Int {
        return (row * numberOfColumns) + column
    }
    
    func rowColumn(index: Int) -> (row: Int, column: Int) {
        return (index / numberOfColumns, index % numberOfColumns)
    }
    
    //----------------------------------------------------------------------------------------
    
    // Testing
    
    let oneDim = [
           0,    1,    2,    3,    4,
           5,    6,    7,    8,    9,
          10,   11,   12,   13,   14,
    ]
    
    let twoDim = [
        [  0,    1,    2,    3,    4 ],
        [  5,    6,    7,    8,    9 ],
        [ 10,   11,   12,   13,   14 ],
    ]
    
    for i1 in 0..<numberOfIndexes {
        let v1 = oneDim[i1]
        let rc = rowColumn(index: i1)
        let i2 = index(row: rc.row, column: rc.column)
        let v2 = oneDim[i2]
        let v3 = twoDim[rc.row][rc.column]
        print(i1, v1, i2, v2, v3, rc)
        assert(i1 == i2)
        assert(v1 == v2)
        assert(v2 == v3)
    }
    
    /* Output:
    0 0 0 0 0 (row: 0, column: 0)
    1 1 1 1 1 (row: 0, column: 1)
    2 2 2 2 2 (row: 0, column: 2)
    3 3 3 3 3 (row: 0, column: 3)
    4 4 4 4 4 (row: 0, column: 4)
    5 5 5 5 5 (row: 1, column: 0)
    6 6 6 6 6 (row: 1, column: 1)
    7 7 7 7 7 (row: 1, column: 2)
    8 8 8 8 8 (row: 1, column: 3)
    9 9 9 9 9 (row: 1, column: 4)
    10 10 10 10 10 (row: 2, column: 0)
    11 11 11 11 11 (row: 2, column: 1)
    12 12 12 12 12 (row: 2, column: 2)
    13 13 13 13 13 (row: 2, column: 3)
    14 14 14 14 14 (row: 2, column: 4)
    */
    
    0 讨论(0)
  • 2021-01-31 20:00

    It's easy:row-major and column-major are from the glUniformMatrix*()'s perspective. actually, matrix never changed, it is alwarys:

    What is difference is matrix class realization. It deterimins how 16 floats stored as parameter passing to glUniformMatrix*()

    If you use row-major matrix, memory of 4x4 matrix is: (a11, a12, a13, a14, a21, a22, a23, a24, a31, a32, a33, a34, a41, a42, a43, a44), else for column-major is: (a11, a21, a31, a41, a12, a22, a32, a42, a13, a23, a33, a43, a41, a42, a43, a44).

    Because glsl is column-major matrix, so it will read the 16 float data (b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16) as

    Since in row-major, a11=b1, a12=b2, a13=b3, a14=b4, a21=b5, a22=b6,...so in glsl matrix is changed to

    while in column-major: a11=b1, a21=b2, a31=b3, a41=b4, a12=b5, a22=b6,...so in glsl matrix is changed to

    which is the same as the orign. So row-major needing a transpose while column-major not.

    Hoping this can solve your confusion.

    0 讨论(0)
  • 2021-01-31 20:01

    A short addendum to above answers. In terms of C, where memory is accessed almost directly, the row-major or column-major order affects your program in 2 ways: 1. It affects the layout of your matrix in memory 2. The order of element access that must be kept - in the form of ordering loops.

    1. is explained quite thoroughly in the previous answers, so I will add to 2.

    eulerworks answer points out that in his example, using row major matrix brought about significant slow down in calculation. Well, he is right, but the result can be at the same time reversed.

    The loop order was for(over rows) { for(over columns) { do something over a matrix } }. Which means that the dual loop will access elements in a row and then move over to the next row. For example, A(0,1) -> A(0,2) -> A(0,3) -> ... -> A(0,N_ROWS) -> A(1,0) -> ...

    In such case, if A was stored in row major format there would be minimal cache misses since the elements will probably lined up in linear fashion in memory. Otherwise in column-major format, memory access will jump around using N_ROWS as a stride. So row-major is faster in the case.

    Now, we can actually switch the loop, such that it will for(over columns) { for(over rows) { do something over a matrix } }. For this case, the result will be exactly the opposite. Column major calculation will be faster since the loop will read elements in columns in linear fashion.

    Hence, you might as well remember this: 1. Selecting row major or column major storage format is up to your taste, even though the traditional C programming community seem to prefer the row-major format. 2. Although you are pretty much free to choose whatever you may like, you need to be consistent with the notion of the indexing. 3. Also, this is quite important, keep in mind that when writing down your own algorithms, try to order the loops so that it will honor the storage format of your choice. 4. Be consistent.

    0 讨论(0)
提交回复
热议问题