Vectores: indexación por posición

Vectores: indexación por posición

Un vector es un arreglo: una secuencia de números almacenados uno junto a otro en memoria. En la lección anterior sumaste uno moviendo un puntero hacia adelante 4 bytes por cada elemento. Ese mismo método funciona aquí. Hay otra forma común de llegar a un elemento: por índice. Un índice es la posición de un elemento contada desde el inicio, donde el primer elemento tiene índice 0, el segundo tiene índice 1, y así sucesivamente.

Suma un vector avanzando un puntero

Suma un vector avanzando un puntero
.data
a: .word 5, 10, 15, 20 # cuatro elementos
.text
la t0, a # t0 = dirección de a
li t1, 4 # t1 = número de elementos restantes
li t2, 0 # t2 = suma acumulada
loop:
beq t1, zero, done
lw t3, 0(t0) # carga el elemento actual
add t2, t2, t3 # suma al total
addi t0, t0, 4 # avanza a la siguiente palabra (4 bytes)
addi t1, t1, -1 # uno menos
j loop
done:
mv a0, t2 # imprime el total: 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

El bucle se ejecuta de la siguiente manera. t0 contiene la dirección de a, y t1 contiene el número de elementos restantes, comenzando en 4. En cada pasada, termina el bucle cuando el contador llega a cero. carga el elemento en la dirección de t0. suma ese valor al total acumulado. avanza el puntero a la siguiente palabra. disminuye el contador. Después de cuatro pasadas (5 + 10 + 15 + 20), done imprime 50. Este es el mismo patrón usado en la lección de memoria, ahora aplicado a un vector.

Del índice a la dirección

La indexación calcula una dirección a partir de un puntero base y una posición: address = base + index * 4. El 4 es el tamaño de una palabra en bytes. Un compilador genera este mismo cálculo para a[i] en un lenguaje como C. El índice en sí nunca accede a la memoria. Solo lo hace la dirección calculada a partir de él.

Índice a dirección, usando un desplazamiento
slli t5, t3, 2 # t5 = índice * 4 (tamaño de una palabra)
add t6, t0, t5 # t6 = dirección de element[index]
lw t6, 0(t6) # t6 = element[index]

desplaza el índice en t3 dos bits a la izquierda, lo que lo multiplica por 4 (dos duplicaciones: 2 x 2), el tamaño de una palabra. Sumar el resultado al puntero base da la dirección de element[index]. Este desplazamiento es el mismo método de potencias de dos de la lección de aritmética, y es la forma estándar de escalar un índice por el tamaño de una palabra.

Cálculo de direcciones
dirección=base+0×4=base+0
a[0]3
0x10010000
a[1]6
0x10010004
a[2]9
0x10010008
a[3]12
0x1001000c

a[0]: índice 0, desplazamiento 0.

La barra del puntero y la insignia hexadecimal se mueven juntas mientras el índice recorre 0, 1, 2, 3. Presentan el mismo hecho en dos formas: i como posición, y la dirección que esa posición produce después de que la escala por 4 y la suma a la base. Los números hexadecimales son las direcciones reales que ocupa a cuando el simulador ejecuta este programa. El objetivo es predecir la siguiente dirección antes de que aparezca. Eso te permite leer dentro de un bucle incremental, o a[i] en un lenguaje tipo C, y visualizar la dirección de memoria que toca en lugar de tratar la notación como una caja negra.

Sumar un vector por índice

Suma un vector usando un índice
.data
a: .word 5, 10, 15, 20 # cuatro elementos
.text
la t0, a # t0 = dirección base de a
li t1, 4 # t1 = número de elementos
li t2, 0 # t2 = índice, comienza en 0
li t3, 0 # t3 = total acumulado
loop:
beq t2, t1, done
slli t4, t2, 2 # t4 = índice * 4 (desplazamiento en bytes)
add t5, t0, t4 # t5 = dirección de a[index]
lw t5, 0(t5) # t5 = a[index]
add t3, t3, t5 # total += a[index]
addi t2, t2, 1 # avanza al siguiente índice
j loop
done:
mv a0, t3 # imprime el total: 5+10+15+20 = 50
li a7, 1
ecall
li a7, 10
ecall

El bucle se ejecuta de la siguiente manera. t2 es el índice, comenzando en 0. En cada pasada, termina el bucle cuando el índice llega a 4, el número de elementos contenido en t1. convierte el índice en un desplazamiento en bytes. suma ese desplazamiento a la dirección base en t0 para producir la dirección de a[index]. carga el valor almacenado allí. Ese valor se suma al total acumulado en t3, y avanza al siguiente índice. Después de cuatro pasadas (5 + 10 + 15 + 20), done imprime 50.

Suma de dos vectores, elemento por elemento

c[i] = a[i] + b[i]
.data
a: .word 3, 6, 9, 12 # primer vector
b: .word 1, 2, 3, 4 # segundo vector
c: .space 16 # espacio para 4 palabras de resultado
.text
la t0, a # dirección base de a
la t1, b # dirección base de b
la t2, c # dirección base de c
li t3, 0 # índice, empieza en 0
li t4, 4 # número de elementos
li s0, 0 # total acumulado
loop:
beq t3, t4, done
slli t5, t3, 2 # desplazamiento en bytes = índice * 4
add t6, t0, t5 # dirección de a[index]
lw t6, 0(t6) # valor de a[index]
add a0, t1, t5 # dirección de b[index]
lw a0, 0(a0) # valor de b[index]
add t6, t6, a0 # a[index] + b[index]
add a0, t2, t5 # dirección de c[index]
sw t6, 0(a0) # c[index] = a[index] + b[index]
add s0, s0, t6 # total += c[index]
addi t3, t3, 1 # avanza al siguiente índice
j loop
done:
mv a0, s0 # imprime el total: 4+8+12+16 = 40
li a7, 1
ecall
li a7, 10
ecall

El bucle se ejecuta de la siguiente manera. convierte el índice t3 en un desplazamiento en bytes. Sumarlo a cada puntero base (t0, t1, t2) da las direcciones de a[i], b[i] y c[i]. En cada pasada, ambos elementos se cargan, se suman, se almacenan en c y se añaden al total acumulado en s0. avanza al siguiente índice, y el bucle se repite hasta que se procesan los cuatro elementos.

💡
Este patrón de indexación, base + índice * tamaño del elemento, es como se compila todo acceso a un arreglo, en cualquier lenguaje. Tenlo en cuenta: la próxima lección usa la misma idea dos veces a la vez para acceder a una matriz.