it-swarm.com.de

Row-Major vs. Column-Major-Verwirrung

Ich habe viel darüber gelesen, je mehr ich lese, desto verwirrter werde ich.

Mein Verständnis: In Zeilenhauptzeilen werden zusammenhängend im Speicher gespeichert, in Spaltenhauptspalten werden zusammenhängend im Speicher gespeichert. Wenn wir also eine Folge von Zahlen [1, ..., 9] haben und diese in einer Reihenmatrix speichern wollen, erhalten wir:

|1, 2, 3|
|4, 5, 6|
|7, 8, 9|

während die Kolumne major (korrigiere mich, wenn ich falsch liege):

|1, 4, 7|
|2, 5, 8|
|3, 6, 9|

das ist effektiv die Transponierung der vorherigen Matrix.

Meine Verwirrung: Nun, ich sehe keinen Unterschied. Wenn wir beide Matrizen durchlaufen (nach Zeilen in der ersten und nach Spalten in der zweiten), werden die gleichen Werte in derselben Reihenfolge behandelt: 1, 2, 3, ..., 9

Sogar die Matrixmultiplikation ist gleich, wir nehmen die ersten zusammenhängenden Elemente und multiplizieren sie mit den zweiten Matrixspalten. Sagen wir also, wir haben die Matrix M:

|1, 0, 4| 
|5, 2, 7| 
|6, 0, 0|

Wenn wir die vorherige Zeilenmatrix R mit M multiplizieren, ist dies R x M, und wir erhalten:

|1*1 + 2*0 + 3*4, 1*5 + 2*2 + 3*7, etc|
|etc.. |
|etc.. |

Wenn Sie die Spaltenmatrix C mit M multiplizieren, dh C x M, indem Sie die Spalten von C anstelle ihrer Zeilen verwenden, erhalten Sie dasselbe Ergebnis von R x M.

Ich bin wirklich verwirrt. Wenn alles gleich ist, warum gibt es diese beiden Begriffe überhaupt? Ich meine sogar in der ersten Matrix R, ich könnte mir die Zeilen ansehen und sie als Spalten betrachten ...

Fehlt mir etwas? Was impliziert Row-Major vs. Col-Major in meiner Matrixmathematik? Ich habe in meinen linearen Algebra-Klassen immer gelernt, dass wir Zeilen aus der ersten Matrix mit Spalten aus der zweiten Matrix multiplizieren. Ändert sich das, wenn sich die erste Matrix im Spaltenhauptbereich befindet? Müssen wir jetzt die Spalten mit den Spalten aus der zweiten Matrix multiplizieren, wie ich es in meinem Beispiel getan habe, oder war das einfach falsch?

Eventuelle Klarstellungen werden sehr geschätzt!

EDIT: Eine der anderen Hauptverwirrungsquellen, die ich habe, ist GLM ... Also schwebe ich über den Matrixtyp und drücke F12, um zu sehen, wie es implementiert wird. Dort sehe ich ein Vektorarray, also, wenn wir haben Bei einer 3x3-Matrix haben wir ein Array von 3 Vektoren. Wenn ich mir den Typ dieser Vektoren ansehe, habe ich 'col_type' gesehen, also nahm ich an, dass jeder dieser Vektoren eine Spalte darstellt, und wir haben also ein Spalten-Hauptsystem, oder?

Nun, ich weiß es nicht ehrlich. Ich habe diese Druckfunktion geschrieben, um meine Übersetzungsmatrix mit glm zu vergleichen. Ich sehe den Translationsvektor in glm in der letzten Zeile und meiner ist in der letzten Spalte ... 

 enter image description here

Dies führt nur zu mehr Verwirrung. Sie können deutlich sehen, dass jeder Vektor in der glmTranslate-Matrix eine Zeile in der Matrix darstellt. Das heißt also, dass die Matrix reihenmächtig ist, oder? Was ist mit meiner Matrix? (Ich verwende ein Float-Array [16]) Die Umrechnungswerte befinden sich in der letzten Spalte. Bedeutet das, dass meine Matrix Column-Major ist und jetzt nicht? versucht den Kopf vom Drehen abzuhalten

11
vexe

Schauen wir uns zuerst die Algebra an. Algebra hat nicht einmal eine Vorstellung von "Speicherlayout" und so.

Aus einem algebraischen Pov kann eine reale MxN-Matrix auf einen | R ^ N-Vektor auf der rechten Seite einwirken und einen | R ^ M-Vektor ergeben. 

Wenn Sie also an einer Prüfung teilnehmen und eine MxN-Matrix und einen | R ^ N-Vektor erhalten haben, könnten Sie sie mit trivialen Operationen multiplizieren und ein Ergebnis erhalten, dh ob das Ergebnis richtig oder falsch ist, hängt nicht davon ab, ob der Software, die Ihr Professor verwendet, um Ihre Ergebnisse intern zu überprüfen, verwendet das Column-Major- oder das Zeilen-Major-Layout. es hängt nur davon ab, ob Sie die Kontraktion jeder Zeile der Matrix mit der (einzelnen) Spalte des Vektors richtig berechnet haben. 

Um eine korrekte Ausgabe zu erzielen, muss die Software - wie auch immer - im Wesentlichen jede Zeile der Matrix mit dem Spaltenvektor kontrahieren, genau wie Sie es in der Prüfung getan haben. 


Daher ist der Unterschied zwischen Software, die die Spaltenspalte ausrichtet, und Software, die das Zeilenhauptlayout ist nicht das, was berechnet, sondern nur wie.

Genauer gesagt, der Unterschied zwischen diesen Layouts in Bezug auf die Kontraktion der einzelnen Zeile in der ersten Zeile mit dem Spaltenvektor ist gerade die zu bestimmenden Mittel

Where is the next element of the current row?
  • Bei einem großen Zeilenlayout ist es das Element nur im nächsten Speicherbereich 
  • Für ein Column-Major-Layout ist es das Element in den Bucket-M-Buckets.

Und das ist es.


Um Ihnen zu zeigen, wie diese Spalten-/Reihenmagie in der Praxis beschworen wird:

Sie haben Ihre Frage nicht mit "c ++" markiert, aber da Sie ' glm ' erwähnt haben, gehe ich davon aus, dass Sie mit C++ auskommen können.

In der C++ - Standardbibliothek gibt es ein berüchtigtes Ungetüm namens valarray , das neben anderen kniffligen Funktionen Überlastungen von operator [] aufweist, von denen einer annehmen kann a std::slice (was im Wesentlichen eine sehr langweilige Sache ist und nur aus drei Ganzzahl-Zahlen besteht).

Dieses kleine Slice-Ding hat jedoch alles, was man für den Zugriff auf einen spaltenweisen Spaltenspeicher oder einen Spaltenspeicher benötigen würde - es hat einen Anfang, eine Länge und einen Schritt - letzteres repräsentiert das " Entfernung zum nächsten Eimer ", sagte ich.

4
decltype_auto

Ich denke, Sie mischen ein Implementierungsdetail mit der Verwendung, wenn Sie so wollen. 

Beginnen wir mit einem zweidimensionalen Array oder einer Matrix:

    | 1  2  3 |
    | 4  5  6 |
    | 7  8  9 |

Das Problem ist, dass der Computerspeicher ein eindimensionales Byte-Array ist. Um unsere Diskussion zu vereinfachen, lassen Sie uns die einzelnen Bytes in Gruppen von vier gruppieren, also haben wir etwas, das so aussieht (+ + + stellt ein Byte dar, vier Bytes stellen einen ganzzahligen Wert dar (angenommen 32) -Bit-Betriebssysteme):

   -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
    |       |       |       |       |       |       |       |       |  
   -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
       \/                   \       /
      one byte               one integer

    low memory    ------>                          high memory

Eine andere Darstellungsweise 

Die Frage ist also, wie eine zweidimensionale Struktur (unsere Matrix) auf diese eindimensionale Struktur (d. H. Speicher) abgebildet werden kann. Dafür gibt es zwei Möglichkeiten.

  1. Reihenreihenfolge: In dieser Reihenfolge legen wir die erste Reihe zuerst und dann die zweite usw. in den Speicher. Auf diese Weise hätten wir folgendes im Gedächtnis:

    -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   1   |   2   |   3   |   4   |   5   |   6   |   7   |   8   |   9   |
    -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

Mit dieser Methode können wir ein gegebenes Element unseres Arrays finden, indem Sie die folgende Arithmetik ausführen. Angenommen, wir möchten auf das Element $ M_ {ij} $ des Arrays zugreifen. Wenn wir davon ausgehen, dass wir einen Zeiger auf das erste Element des Arrays haben, beispielsweise ptr, und die Anzahl der Spalten nCol kennen, können wir jedes Element finden, indem:

     $M_{ij} = i*nCol + j$ 

Um zu sehen, wie das funktioniert, betrachten Sie M_ {02} (d. H. Erste Zeile, dritte Spalte - denken Sie daran, dass C null ist.) 

      $M_{02} = 0*3 + 2 = 2

Wir greifen also auf das dritte Element des Arrays zu.

  1. Column-Major-Reihenfolge: In dieser Reihenfolge setzen wir zuerst die erste Spalte und dann die zweite Spalte in den Speicher. Damit hätten wir folgendes im Gedächtnis:

    -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |   1   |   4   |   7   |   2   |   5   |   8   |   3   |   6   |   9   |
    -+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    

Also, die kurze Antwort - Zeilen-Haupt- und Spalten-Haupt-Format - beschreibt, wie die zwei (oder höher) dimensionalen Arrays in ein eindimensionales Speicherfeld abgebildet werden.

Hoffe das hilft . T.

9
thurizas

Du hast recht. Es spielt keine Rolle, ob ein System die Daten in einer Zeilenstruktur oder in einer Spaltenstruktur speichert. Es ist wie ein Protokoll. Computer: "Hey, Mensch. Ich werde Ihr Array auf diese Weise speichern. Kein Problem. Huh?" Wenn es jedoch um Leistung geht, ist es wichtig. Betrachten Sie die folgenden drei Dinge. 

1. Auf die meisten Arrays wird in Reihenreihenfolge zugegriffen.

2. Wenn Sie auf den Speicher zugreifen, wird er nicht direkt aus dem Speicher gelesen. Sie speichern zunächst einige Datenblöcke aus dem Arbeitsspeicher in den Cache und lesen dann Daten aus dem Cache in Ihren Prozessor.

3. Wenn die gewünschten Daten nicht im Cache vorhanden sind, sollte der Cache die Daten erneut aus dem Speicher abrufen

Wenn ein Cache Daten aus dem Speicher abruft, ist die Lokalität wichtig. Das heißt, wenn Sie Daten sparsam im Speicher ablegen, sollte Ihr Cache häufiger Daten aus dem Speicher abrufen. Diese Aktion beeinträchtigt die Leistung Ihres Programms, da der Zugriff auf den Speicher viel langsamer ist (über 100-mal!) Als der Zugriff auf den Cache. Je weniger Sie auf den Speicher zugreifen, desto schneller ist Ihr Programm. Dieses Zeilenmajorarray ist daher effizienter, da der Zugriff auf seine Daten mit größerer Wahrscheinlichkeit lokal erfolgt.

3
Y.C.Jung

Egal was Sie verwenden: Seien Sie einfach konsequent!

Row Major oder Column Major ist nur eine Konvention. Macht nichts C verwendet Zeilenhaupt, Fortran verwendet Spalte. Beide arbeiten. Verwenden Sie den Standard in Ihrer Programmiersprache/-umgebung.

Mismatching der beiden wird! @ # $ Zeug

Wenn Sie die Zeilenhauptadressierung für eine in colum major gespeicherte Matrix verwenden, können Sie das falsche Element erhalten, über das Ende des Arrays hinaus lesen usw.

Row major: A(i,j) element is at A[j + i * n_columns];  <---- mixing these up will
Col major: A(i,j) element is at A[i + j * n_rows];     <---- make your code fubar

Es ist falsch zu sagen, dass der Code für die Matrixmultiplikation für Zeilenhaupt und Spaltenhaupt gleich ist

(Natürlich ist die Matrixmultiplikation die gleiche.) Stellen Sie sich vor, Sie haben zwei Arrays im Speicher:

X = [x1, x2, x3, x4]    Y = [y1, y2, y3, y4]

Wenn Matrizen in der Spalte major gespeichert sind, sind X, Y und X * Y:

IF COL MAJOR: [x1, x3  *  [y1, y3    =   [x1y1+x3y2, x1y3+x3y4
               x2, x4]     y2, y4]        x2y1+x4y2, x2y3+x4y4]

Wenn Matrizen in der Zeile major gespeichert sind, sind X, Y und X * Y:

IF ROW MAJOR:  [x1, x2    [y1, y2     = [x1y1+x2y3, x1y2+x2y4;
                x3, x4]    y3, y4]       x3y1+x4y3, x3y2+x4y4];

X*Y in memory if COL major   [x1y1+x3y2, x2y1+x4y2, x1y3+x3y4, x2y3+x4y4]
              if ROW major   [x1y1+x2y3, x1y2+x2y4, x3y1+x4y3, x3y2+x4y4]

Hier ist nichts tiefes los. Es sind nur zwei verschiedene Konventionen. Es ist wie in Meilen oder Kilometern zu messen. Entweder funktioniert, Sie können einfach nicht zwischen den beiden hin- und herschalten, ohne zu konvertieren!

2
Matthew Gunn

Ok, wenn man bedenkt, dass das Wort "Verwirrung" buchstäblich im Titel vorkommt, kann ich das Ausmaß der ... Verwirrung verstehen.

Erstens ist dies absolut ein echtes Problem

Niemals, NIEMALS erliegen die Idee, dass "es verwendet wird, aber ... PCs heutzutage ..."

Die Hauptprobleme hier sind: -Cache eviction strategy (LRU, FIFO, etc.) as @Y.C.Jung was beginning to touch on -Branch prediction -Pipelining (it's depth, etc) -Actual physical memory layout -Size of memory -Architecture of machine, (ARM, MIPS, Intel, AMD, Motorola, etc.)

Diese Antwort konzentriert sich auf die Harvard-Architektur von Neumann, da sie für den aktuellen PC am besten geeignet ist.

Die Speicherhierarchie:

https://en.wikipedia.org/wiki/File:ComputerMemoryHierarchy.svgis

Ist ein Nebeneinander von Kosten und Geschwindigkeit.

Für das heutige Standard-PC-System würde dies ungefähr so ​​aussehen: SIZE: 500GB HDD > 8GB RAM > L2 Cache > L1 Cache > Registers. SPEED: 500GB HDD < 8GB RAM < L2 Cache < L1 Cache < Registers.

Dies führt zur Idee der zeitlichen und räumlichen Lokalität. Das eine bedeutet , wie Ihre Daten organisiert sind (Code, Arbeitssatz usw.), das andere bedeutet physisch , wo Ihre Daten sind in "Speicher" organisiert.

Da es sich bei den "meisten" heutigen PCs um Little-Endian- (Intel-) Computer handelt, werden die Daten in einer bestimmten Little-Endian-Reihenfolge in den Speicher geladen . Es unterscheidet sich grundlegend von Big-Endian.

https://www.cs.umd.edu/class/sum2003/cmsc311/Notes/Data/endian.html (deckt es eher ab ... swiftly;))

(Zur Vereinfachung dieses Beispiels werde ich sagen, dass Dinge in einzelnen Einträgen passieren, dies ist falsch, auf ganze Cache-Blöcke wird normalerweise zugegriffen und mein Hersteller variiert drastisch, viel weniger Modell).

Also, jetzt, da wir das haben, ist unser Weg, wenn hypothetisch Ihr Programm 1GB of data from your 500GB HDD, geladen in dein 8GB of RAM, dann in die cache Hierarchie, dann schließlich registers, wo Ihr Programm den ersten Eintrag aus Ihrer frischesten Cache-Zeile gelesen hat, nur um Ihren zweiten (in IHREM Code) gewünschten Eintrag zu erhalten sitze im next cache line, (dh die nächste [~ # ~] Zeile [~ # ~] anstelle von Spalte Sie hätten einen Cache [~ # ~] vermissen [~ # ~] .

Angenommen, der Cache ist voll, weil er bei einem Fehler klein ist Gemäß dem Räumungsschema würde eine Linie geräumt, um Platz für die Linie zu schaffen, die die nächsten Daten enthält, die Sie benötigen. Wenn sich dieses Muster wiederholen würde, hätten Sie einen [~ # ~] Fehlschlag [~ # ~] am [~ # ~] bei jedem [~ # ~] versuchten Datenabruf!

Schlimmer noch, Sie würden Zeilen entfernen, die tatsächlich gültige Daten enthalten, die Sie in Kürze benötigen. Sie müssen sie also WIEDER und WIEDER abrufen .

Der Begriff dafür heißt: thrashing

https://en.wikipedia.org/wiki/Thrashing_ (computer_science) und kann in der Tat einen schlecht geschriebenen/fehler zum Absturz bringen anfälliges System. (Denken Sie an Windows [~ # ~] bsod [~ # ~] ) ....

Andererseits, wenn Sie die Daten richtig angeordnet hätten (d. H. Row Major) ... hätten Sie immer noch Fehler!

Aber diese Fehler würden nur am Ende jedes Abrufs auftreten, nicht bei JEDEM versuchten Abruf. Dies führt zu Größenordnungen von Unterschieden in der System- und Programmleistung.

Sehr sehr einfaches Snippet:

#include<stdio.h>

#define NUM_ROWS 1024
#define NUM_COLS 1024

int COL_MAJOR [NUM_ROWS][NUM_COLS];

int main (void){
        int i=0, j=0;
        for(i; i<NUM_ROWS; i++){
                for(j; j<NUM_COLS; j++){
                        COL_MAJOR[j][i]=(i+j);//NOTE i,j order here!
                }//end inner for
        }//end outer for
return 0;
}//end main

Jetzt kompilieren Sie mit: gcc -g col_maj.c -o col.o

Führen Sie nun Folgendes aus: time ./col.oreal 0m0.009suser 0m0.003ssys 0m0.004s

Wiederholen Sie nun für ROW-Dur:

#include<stdio.h>

#define NUM_ROWS 1024
#define NUM_COLS 1024

int ROW_MAJOR [NUM_ROWS][NUM_COLS];

int main (void){
        int i=0, j=0;
        for(i; i<NUM_ROWS; i++){
                for(j; j<NUM_COLS; j++){
                        ROW_MAJOR[i][j]=(i+j);//NOTE i,j order here!
                }//end inner for
        }//end outer for
return 0;
}//end main

Kompilieren: terminal4$ gcc -g row_maj.c -o row.o Ausführen: time ./row.oreal 0m0.005suser 0m0.001ssys 0m0.003s

Wie Sie sehen, war der Zeilensprung deutlich schneller.

Nicht überzeugt? Wenn Sie ein drastischeres Beispiel sehen möchten: Machen Sie die Matrix 1000000 x 1000000, initialisieren Sie sie, transponieren Sie sie und drucken Sie sie auf stdout. `` `

(Beachten Sie, dass Sie auf einem * NIX-System ulimit unlimited einstellen müssen.)

FRAGEN mit meiner Antwort: -Optimizing compilers, they change a LOT of things! -Type of system -Please point any others out -This system has an Intel i5 processor

1
eulerworks

In Anbetracht der obigen Erläuterungen wird hier ein Code-Snippet gezeigt, der das Konzept veranschaulicht.

//----------------------------------------------------------------------------------------
// 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
eholley

Ein kurzer Nachtrag zu den obigen Antworten ..__ In Bezug auf C, bei dem auf Speicher fast direkt zugegriffen wird, wirkt sich die Reihenfolge der Zeilen- oder Spaltenhauptteile auf zwei Arten auf Ihr Programm aus: 1. Dies hat Auswirkungen auf das Layout Ihrer Matrix im Speicher 2. Die Reihenfolge des Elementzugriffs, die beibehalten werden muss - in Form von Bestellschleifen.

  1. wird in den vorangegangenen Antworten ausführlich erklärt, daher werde ich zu 2 hinzufügen.

die Antwort von eulerworks weist darauf hin, dass die Verwendung der Zeilenmatrix in seinem Beispiel die Berechnungen erheblich verlangsamt. Nun, er hat recht, aber das Ergebnis kann gleichzeitig umgekehrt werden.

Die Schleifenreihenfolge war für (über Zeilen) {für (über Spalten) {etwas über einer Matrix tun}}. Dies bedeutet, dass die Doppelschleife auf Elemente in einer Reihe zugreift und dann zur nächsten Reihe übergeht. Zum Beispiel: A (0,1) -> A (0,2) -> A (0,3) -> ... -> A (0, N_ROWS) -> A (1,0) -> .. .

Wenn A in einem solchen Format im Zeilenhauptformat gespeichert wird, würde dies zu minimalen Cache-Fehlern führen, da die Elemente im Speicher wahrscheinlich linear angeordnet sind. Andernfalls springt im Hauptspaltenformat der Speicherzugriff unter Verwendung von N_ROWS als Schritt. Reihenmajor ist also schneller im Fall.

Jetzt können wir die Schleife tatsächlich so umschalten, dass sie für (über Spalten) {für (über Zeilen) {etwas über einer Matrix}} tut. In diesem Fall ist das Ergebnis genau das Gegenteil. Die Berechnung der Spaltenhauptlänge ist schneller, da die Schleife Elemente in Spalten linear liest.

Daher können Sie sich genauso gut daran erinnern: 1. Die Wahl des Zeilenformats oder des Spaltenformats ist Ihrem Geschmack überlassen, auch wenn die traditionelle C-Programmierszene scheinbar das Zeilenhauptformat bevorzugt. 2. Obwohl Sie ziemlich frei wählen können, was Sie möchten, müssen Sie mit der Vorstellung der Indizierung vereinbar sein 3. Dies ist auch sehr wichtig. Denken Sie daran, wenn Sie Ihre eigenen Algorithmen aufschreiben, versuchen Sie, die Schleifen so zu ordnen, dass sie das Speicherformat Ihrer Wahl berücksichtigen. 4. Seien Sie konsequent.

0
Juwhan Kim

Heute gibt es keinen Grund, eine andere als die Column-Major-Reihenfolge zu verwenden. Es gibt mehrere Bibliotheken, die dies in c/c ++ unterstützen (Eigen, Gürteltier, ...). Darüber hinaus ist die Column-Major-Order natürlicher, z. Bilder mit [x, y, z] werden scheibenweise in Datei gespeichert, dies ist die Reihenfolge der Spalten. In zwei Dimensionen kann es verwirrend sein, eine bessere Reihenfolge zu wählen. In einer höheren Dimension ist es jedoch klar, dass die Kolumnenordnung in vielen Situationen die einzige Lösung ist.

Autoren von C erstellten ein Konzept von Arrays, aber vielleicht hatten sie nicht damit gerechnet, dass jemand es als Matrizen verwendet hatte. Ich wäre selbst schockiert, wenn ich sehen würde, wie Arrays dort eingesetzt werden, wo bereits alles in Fortran und Column Major angeordnet wurde. Ich denke, dass die Reihenhauptordnung einfach eine Alternative zur Reihenhauptordnung ist, aber nur in Situationen, in denen sie wirklich benötigt wird (vorläufig weiß ich noch nichts).

Es ist seltsam, dass immer noch jemand eine Bibliothek in Reihenreihenfolge erstellt. Es ist unnötige Verschwendung von Energie und Zeit. Ich hoffe, dass eines Tages alles in Ordnung kommt und alle Verwirrungen verschwinden. 

0
Paul