Haciendo matemáticas

Haciendo matemáticas

Todos los cálculos se realizan entre registros. Una instrucción aritmética nombra el destino primero, seguido de las dos fuentes que lee: significa dest = src1 + src2.

Operación aritmética
t2, t0, t1←add
t0 = 7t1 = 5+t2 = 12

add coloca t0 + t1 en t2.

Las dos líneas que entran por la izquierda son t0 y t1, siempre en ese orden. Entran en la misma forma independientemente de la operación que se ejecute: suma, resta, multiplicación, división o resto. Entran dos valores, ocurre una operación y sale un resultado hacia t2 a la derecha. nombra t2 primero porque ahí es donde aterriza el resultado, lo que coincide con la única regla de orden que sigue toda instrucción aritmética de esta lección.

Suma y resta

toma los números contenidos en dos registros y almacena su suma en un tercero. hace lo mismo para la resta: calcula t0 - t1. Ambas instrucciones leen únicamente de registros.

Registrar aritmética
add t2, t0, t1 # t2 = t0 + t1
sub t2, t0, t1 # t2 = t0 - t1

Una cosa que hay que saber: un registro solo contiene 32 bits, así que hay un límite. Si un resultado es demasiado grande para caber, no se genera ningún error. El valor se desborda silenciosamente hacia números muy bajos y la ejecución continúa. Los valores cotidianos no alcanzarán este límite, pero vale la pena conocer el techo.

Para usar un número fijo en lugar de un segundo registro, añade la letra i, que significa inmediato: suma la constante 1. No existe subi, así que para restar una constante se suma una negativa: .

💡
suma una constante. suma dos registros. Confundir ambas es el error más común de los principiantes.

Multiplicar y dividir

multiplica dos registros. los divide como números enteros y descarta la fracción, así que 7 / 2 da 3. da el resto, así que 7 % 2 da 1. La división nunca provoca un fallo. Dividir entre cero devuelve -1.

Multiplicar, dividir, resto
mul t2, t0, t1 # t2 = t0 * t1
div t2, t0, t1 # t2 = t0 / t1 (entero)
rem t2, t0, t1 # t2 = t0 % t1 (resto)

Poniéndolo todo junto

Suma dos números y muestra el resultado
li t0, 7
li t1, 5
add t1, t0, t1 # t1 = 7 + 5 = 12
mv a0, t1 # el servicio de impresión lee a0
li a7, 1
ecall
li a7, 10
ecall

carga 7 en t0. carga 5 en t1. los suma y escribe 12 en t1. copia el resultado en a0, porque el servicio de impresión siempre lee su valor de a0. Luego selecciona el servicio de imprimir entero y lo ejecuta. Finalmente, y terminan el programa.

Extra: multiplicar con desplazamientos

Cuando el factor es una potencia de dos, existe un método más rápido que . (desplazamiento lógico a la izquierda) mueve los bits de un registro hacia la izquierda, y cada posición que desplazas duplica el valor: desplaza 1 para multiplicar por 2, 2 para 4, 3 para 8. Desplazar cuesta menos que multiplicar, así que los compiladores lo usan a menudo.

Multiplicar por 8 utilizando desplazamientos
li t0, 5 # empieza con 5
# desplaza 3 bits a la izquierda (5 * 2^3 = 5 * 8)
sll a0, t0, 3 # a0 = 40
li a7, 1 # imprimir entero
ecall
li a7, 10
ecall

pone 5 en t0. desplaza sus bits tres posiciones a la izquierda. Cada posición duplica el valor, así que 5 se duplica tres veces (5, 10, 20, 40), dando 40 en a0. El resto sigue el patrón de impresión de antes. Intenta cambiar el 3 por un 1 o un 2 y predice el resultado antes de ejecutarlo.

Multiplicar desplazando
5sll a0, t0, 0
×2 →
10sll a0, t0, 1
×2 →
20sll a0, t0, 2
×2 →
40sll a0, t0, 3
0
0
0
0
0
1
0
1

5 desplazado 0 bits a la izquierda sigue siendo 5.

Las ocho casillas son la forma binaria del número que está encima de ellas, un bit cada una, leídas de izquierda a derecha como de costumbre. Desplazar toda la fila una posición a la izquierda es la misma operación que multiplicar por 2, porque mover un dígito una posición a la izquierda en cualquier base multiplica su valor por esa base. El binario solo tiene dos dígitos, así que el multiplicador es 2. Desplazar tres veces compone esto en una multiplicación por 8, lo que coincide con lo que hace al número 5.