Pergunta

Digamos que eu tenho $t0, e eu gostaria de dividir seu conteúdo inteiro por dois e armazená -lo em $t1.

Meu intestino diz: srl $t1, $t0, 2

... mas isso não seria um problema se ... diga ... o bit mais certo era 1? Ou tudo isso sai na lavagem porque a parte mais à direita (se positivo) faz $t0 Um número ímpar, que se torna mesmo quando dividido?

Ensine -me, ó sábio ...

Foi útil?

Solução

Use Instrução SRA: MUDANÇA ARITHMETICA DIREITA !!

sra $t1, $t0, 1

Divide o conteúdo de $ T0 pela primeira potência de 2.

Descrição: muda um valor de registro diretamente pelo valor da mudança (shamt) e coloca o valor no registro de destino. O bit de sinal é deslocado.

Operação: $ d = $ t >> h;

advance_pc (4);

Sintaxe: SRA $ D, $ T, H

Codificação: 0000 00-- --- t tttt dddd dhhh hh00 0011

Por que isso é importante? Verifique este programa simples que divide um número inteiro (entrada do 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 teste:

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@:~#

Veja o que acontece? o srl a instrução está mudando a parte do sinal

-2 = 0xfffffffe

Se mudarmos um pouco para a direita, obtemos 0x7fffffff

0x7ffffffff = 2147483647

Claro que isso não é um problema quando o número é um número inteiro positivo, porque o bit de sinal é 0.

Outras dicas

Para fazer uma divisão inteira não assinada, isso está certo. Isso funciona apenas para números inteiros não assinados e se você não se importa com a parte fracionária.

Você deseja usar uma quantidade de turno de 1, não 2:

srl $t1, $t0, 1

Se você usar 2, você acabará se dividindo por 4. Em geral, mudando para a direita x divide por 2x.

Se você está preocupado com o "arredondamento" e deseja arredondar, poderá incrementar 1 antes de fazer a mudança lógica (não assinada).

E outros o declararam anteriormente, mas você só muda por 1 para dividir 2. Uma mudança direita por n bits divide por 2^n.

Para usar o arredondamento (arredondando a 0,5 ou superior) com valores de turno de n que não sejam 1, basta adicionar 1 << (n-1) antes do turno.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top