Wektory: indeksowanie według pozycji

Wektory: indeksowanie według pozycji

Wektor to tablica: ciąg liczb przechowywanych obok siebie w pamięci. W poprzedniej lekcji sumowałeś go, przesuwając wskaźnik o 4 bajty dla każdego elementu. Ta sama metoda działa tutaj. Istnieje inny powszechny sposób dotarcia do elementu: przez indeks. Indeks to pozycja elementu liczona od początku, gdzie pierwszy element ma indeks 0, drugi ma indeks 1, i tak dalej.

Zsumuj wektor, przesuwając wskaźnik

Sumuj wektor, przesuwając wskaźnik
.data
a: .word 5, 10, 15, 20 # cztery elementy
.text
la t0, a # t0 = adres a
li t1, 4 # t1 = liczba pozostałych elementów
li t2, 0 # t2 = suma bieżąca
loop:
beq t1, zero, done
lw t3, 0(t0) # wczytuje bieżący element
add t2, t2, t3 # dodaje do sumy
addi t0, t0, 4 # przechodzi do następnego słowa (4 bajty)
addi t1, t1, -1 # o jeden mniej
j loop
done:
mv a0, t2 # wypisuje sumę: 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

Pętla działa następująco. t0 przechowuje adres a, a t1 przechowuje liczbę pozostałych elementów, zaczynając od 4. W każdym przebiegu kończy pętlę, gdy licznik osiągnie zero. ładuje element spod adresu w t0. dodaje tę wartość do sumy bieżącej. przesuwa wskaźnik do następnego słowa. zmniejsza licznik. Po czterech przebiegach (5 + 10 + 15 + 20) done wypisuje 50. To ten sam wzorzec użyty w lekcji o pamięci, teraz zastosowany do wektora.

Od indeksu do adresu

Indeksowanie oblicza adres na podstawie wskaźnika bazowego i pozycji: address = base + index * 4. Liczba 4 to rozmiar słowa w bajtach. Kompilator generuje to samo obliczenie dla a[i] w języku takim jak C. Sam indeks nigdy nie uzyskuje dostępu do pamięci. Robi to tylko obliczony z niego adres.

Indeks na adres, używając przesunięcia
slli t5, t3, 2 # t5 = indeks * 4 (rozmiar słowa)
add t6, t0, t5 # t6 = adres element[index]
lw t6, 0(t6) # t6 = element[index]

przesuwa indeks w t3 o 2 bity w lewo, co mnoży go przez 4 (dwa podwojenia: 2 x 2), rozmiar jednego słowa. Dodanie wyniku do wskaźnika bazowego daje adres element[index]. To przesunięcie to ta sama metoda potęg dwójki z lekcji arytmetyki i standardowy sposób skalowania indeksu przez rozmiar słowa.

Obliczanie adresu
adres=base+0×4=base+0
a[0]3
0x10010000
a[1]6
0x10010004
a[2]9
0x10010008
a[3]12
0x1001000c

a[0]: indeks 0, przesunięcie 0.

Pasek wskaźnika i znaczek szesnastkowy poruszają się razem, gdy indeks przechodzi przez 0, 1, 2, 3. Przedstawiają ten sam fakt w dwóch formach: i jako pozycja oraz adres, który ta pozycja wytwarza po tym, jak skaluje ją przez 4 i dodaje do bazy. Liczby szesnastkowe to rzeczywiste adresy, które zajmuje a, gdy symulator uruchamia ten program. Celem jest przewidzenie następnego adresu, zanim się pojawi. To pozwala czytać wewnątrz pętli inkrementującej lub a[i] w języku typu C i wyobrażać sobie adres pamięci, którego dotyka, zamiast traktować notację jak czarną skrzynkę.

Sumowanie wektora przez indeks

Sumuj wektor, używając indeksu
.data
a: .word 5, 10, 15, 20 # cztery elementy
.text
la t0, a # t0 = adres bazowy a
li t1, 4 # t1 = liczba elementów
li t2, 0 # t2 = indeks, zaczyna się od 0
li t3, 0 # t3 = suma bieżąca
loop:
beq t2, t1, done
slli t4, t2, 2 # t4 = indeks * 4 (przesunięcie bajtowe)
add t5, t0, t4 # t5 = adres a[index]
lw t5, 0(t5) # t5 = a[index]
add t3, t3, t5 # total += a[index]
addi t2, t2, 1 # przechodzi do następnego indeksu
j loop
done:
mv a0, t3 # wypisuje sumę: 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

Pętla działa następująco. t2 to indeks, zaczynający od 0. W każdym przebiegu kończy pętlę, gdy indeks osiągnie 4, liczbę elementów przechowywaną w t1. konwertuje indeks na przesunięcie w bajtach. dodaje to przesunięcie do adresu bazowego w t0, aby uzyskać adres a[index]. ładuje wartość tam przechowywaną. Ta wartość jest dodawana do sumy bieżącej w t3, a przechodzi do następnego indeksu. Po czterech przebiegach (5 + 10 + 15 + 20) done wypisuje 50.

Dodawanie dwóch wektorów, element po elemencie

c[i] = a[i] + b[i]
.data
a: .word 3, 6, 9, 12 # pierwszy wektor
b: .word 1, 2, 3, 4 # drugi wektor
c: .space 16 # miejsce na 4 słowa wyniku
.text
la t0, a # adres bazowy a
la t1, b # adres bazowy b
la t2, c # adres bazowy c
li t3, 0 # indeks, zaczyna się od 0
li t4, 4 # liczba elementów
li s0, 0 # suma bieżąca
loop:
beq t3, t4, done
slli t5, t3, 2 # przesunięcie w bajtach = indeks * 4
add t6, t0, t5 # adres a[index]
lw t6, 0(t6) # wartość a[index]
add a0, t1, t5 # adres b[index]
lw a0, 0(a0) # wartość b[index]
add t6, t6, a0 # a[index] + b[index]
add a0, t2, t5 # adres c[index]
sw t6, 0(a0) # c[index] = a[index] + b[index]
add s0, s0, t6 # suma += c[index]
addi t3, t3, 1 # przechodzi do następnego indeksu
j loop
done:
mv a0, s0 # wypisuje sumę: 4+8+12+16 = 40
li a7, 1
ecall
li a7, 10
ecall

Pętla działa następująco. konwertuje indeks t3 na przesunięcie w bajtach. Dodanie go do każdego wskaźnika bazowego (t0, t1, t2) daje adresy a[i], b[i] i c[i]. W każdym przebiegu oba elementy są ładowane, dodawane do siebie, zapisywane do c i dodawane do sumy bieżącej w s0. przechodzi do następnego indeksu, a pętla powtarza się, aż wszystkie cztery elementy zostaną przetworzone.

💡
Ten wzorzec indeksowania, baza + indeks * rozmiar elementu, to sposób, w jaki kompiluje się każdy dostęp do tablicy, w dowolnym języku. Miej go w pamięci: następna lekcja używa tego samego pomysłu dwukrotnie naraz, aby sięgnąć do macierzy.