Jak powiedzieli inni, problemem jest przechowywanie w pamięci w tablicy: x[i][j]
. Oto trochę wglądu dlaczego:
Masz dwuwymiarowy układ, ale pamięć w komputerze jest z natury jednowymiarowa. Więc kiedy wyobrażasz sobie swoją tablicę w ten sposób:
0,0 | 0,1 | 0,2 | 0,3
----+-----+-----+----
1,0 | 1,1 | 1,2 | 1,3
----+-----+-----+----
2,0 | 2,1 | 2,2 | 2,3
Twój komputer przechowuje go w pamięci jako pojedynczy wiersz:
0,0 | 0,1 | 0,2 | 0,3 | 1,0 | 1,1 | 1,2 | 1,3 | 2,0 | 2,1 | 2,2 | 2,3
W drugim przykładzie uzyskujesz dostęp do tablicy, zapętlając najpierw drugi numer, tj .:
x[0][0]
x[0][1]
x[0][2]
x[0][3]
x[1][0] etc...
Oznacza to, że uderzasz je wszystkie po kolei. Teraz spójrz na pierwszą wersję. Robisz:
x[0][0]
x[1][0]
x[2][0]
x[0][1]
x[1][1] etc...
Ze względu na sposób, w jaki C ułożył tablicę 2-d w pamięci, prosisz ją, aby skakała po całym miejscu. Ale teraz kicker: dlaczego to ma znaczenie? Wszystkie dostępy do pamięci są takie same, prawda?
Nie: z powodu pamięci podręcznych. Dane z pamięci są przenoszone do procesora w małych porcjach (zwanych „liniami pamięci podręcznej”), zwykle 64 bajtami. Jeśli masz 4-bajtowe liczby całkowite, oznacza to, że otrzymujesz 16 kolejnych liczb całkowitych w zgrabnym małym pakiecie. Pobieranie tych fragmentów pamięci jest dość powolne; Twój procesor może wykonać wiele pracy w czasie potrzebnym do załadowania pojedynczej linii pamięci podręcznej.
Spójrzmy teraz na kolejność dostępów: Drugi przykład to (1) chwytanie fragmentu 16 liczb wewnętrznych, (2) modyfikowanie ich wszystkich, (3) powtarzanie 4000 * 4000/16 razy. Jest to przyjemne i szybkie, a procesor zawsze ma coś do pracy.
Pierwszy przykład to (1) weź kawałek 16 liczb wewnętrznych, (2) zmodyfikuj tylko jedną z nich, (3) powtórz 4000 * 4000 razy. Będzie to wymagało 16-krotnej liczby „pobrań” z pamięci. Twój procesor będzie musiał spędzać czas, czekając, aż pojawi się ta pamięć, a gdy siedzisz, marnujesz cenny czas.
Ważna uwaga:
Teraz, gdy znasz odpowiedź, oto interesująca uwaga: nie ma nieodłącznego powodu, że twój drugi przykład musi być szybki. Na przykład w Fortranie pierwszy przykład byłby szybki, a drugi wolny. Wynika to z faktu, że zamiast rozszerzać elementy na koncepcyjne „wiersze”, podobnie jak C, Fortran rozwija się w „kolumny”, tj .:
0,0 | 1,0 | 2,0 | 0,1 | 1,1 | 2,1 | 0,2 | 1,2 | 2,2 | 0,3 | 1,3 | 2,3
Układ C nazywa się „major-row”, a Fortran nazywa się „major-kolumna”. Jak widać, bardzo ważne jest, aby wiedzieć, czy Twój język programowania jest dur-dur czy kolumna-dur! Oto link, aby uzyskać więcej informacji: http://en.wikipedia.org/wiki/Row-major_order