En MIPS, ¿cómo dividir el contenido del registro por dos?
Pregunta
Vamos a decir que tengo $t0
, y me gustaría dividir su contenido enteros en dos, y almacenarlo en $t1
.
Mi instinto dice: srl $t1, $t0, 2
... pero no que sea un problema si ... digamos ... más a la derecha poco era 1? O lo hace todo sale en el lavado ya que el bit más a la derecha (si es positivo) hace $t0
un número impar, lo que hace aún cuando se divide?
Enséñame, oh sabios ...
Solución
SRA Uso de instrucciones: desplazamiento aritmético a la derecha !!
sra $t1, $t0, 1
Divide el contenido de $ t0 por la primera potencia de 2.
Descripción: Cambia un valor de registro derecho por la cantidad de desplazamiento (shamt) y coloca el valor en el destino registro. El bit de signo se desplaza en.
Operación: $ D $ = t >> h;
advance_pc (4);
Sintaxis: SRA $ d, $ t, h
Codificación: 0000 00-- --- t tttt dddd dhhh hh00 0011
¿Por qué es importante esto? Compruebe este sencillo programa que divide un número entero (entrada de programa) por 2.
#include <stdio.h>
/*
* div divides by 2 using sra
* udiv divides by 2 using srl
*/
int div(int n);//implemented in mips assembly.
int udiv(int n);
int main(int argc,char** argv){
if (argc==1) return 0;
int a = atoi(argv[1]);
printf("div:%d udiv:%d\n",div(a),udiv(a));
return 1;
}
//file div.S
#include <mips/regdef.h>
//int div(int n)
.globl div
.text
.align 2
.ent div
div:
sra v0,a0,1
jr ra //Returns value in v0 register.
.end div
//int udiv(int n)
.globl udiv
.text
.align 2
.ent udiv
udiv: srl v0,a0,1 jr ra //Returns value in v0 register. .end udiv
Compilar
root@:/tmp#gcc -c div.S
root@:/tmp#gcc -c main.c
root@:/tmp#gcc div.0 main.o -o test
unidades de prueba:
root@:~# ./test 2
div:1 udiv:1
root@:~# ./test 4
div:2 udiv:2
root@:~# ./test 8
div:4 udiv:4
root@:~# ./test 16
div:8 udiv:8
root@:~# ./test -2
div:-1 udiv:2147483647
root@:~# ./test -4
div:-2 udiv:2147483646
root@:~# ./test -8
div:-4 udiv:2147483644
root@:~# ./test -16
div:-8 udiv:2147483640
root@:~#
Vea lo que sucede? El srl de instrucciones está cambiando el bit de signo
-2 = 0xFFFFFFFE
si cambiamos un poco a la derecha, obtenemos 0x7fffffff
0x7ffffffff = 2147483647
Por supuesto, esto no es un problema cuando el número es un entero positivo, ya que el bit de signo es 0.
Otros consejos
Para hacer una división de entero sin signo, eso es correcto. Esto sólo funciona para enteros sin signo y si no se preocupan por la parte fraccionaria.
Usted tendrá que utilizar una cantidad de cambio de 1, no 2:
srl $t1, $t0, 1
Si utiliza 2, el resultado final será dividir por 4. En general, desplazando a la derecha por x divide por 2 x .
Si usted está preocupado por el "redondeo" y que desea redondear hacia arriba, sólo puede incrementarse en 1 antes de hacer el desplazamiento lógico (sin firmar).
Y otros han declarado previamente, pero sólo cambiar por 1 a dividir por 2. Un desplazamiento a la derecha por la N bits se divide por 2 ^ N.
Para usar redondeo (redondeando hacia arriba en 0,5 o mayor) con valores de desplazamiento de N distintos de 1, sólo tiene que añadir 1 << (N-1) antes del cambio.