Question

Let's say I have $t0, and I'd like to divide its integer contents by two, and store it in $t1.

My gut says: srl $t1, $t0, 2

... but wouldn't that be a problem if... say... the right-most bit was 1? Or does it all come out in the wash because the right-most bit (if positive) makes $t0 an odd number, which becomes even when divided?

Teach me, O wise ones...

Was it helpful?

Solution

Use instruction sra: Shift right arithmetic !!

sra $t1, $t0, 1

Divides the content of $t0 by the first power of 2.

Description: Shifts a register value right by the shift amount (shamt) and places the value in the destination register. The sign bit is shifted in.

Operation: $d = $t >> h;

advance_pc (4);

Syntax: sra $d, $t, h

Encoding: 0000 00-- ---t tttt dddd dhhh hh00 0011

Why is this important? Check this simple program that divides an integer number (program's input) by 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

Compile

root@:/tmp#gcc -c div.S
root@:/tmp#gcc -c main.c
root@:/tmp#gcc div.0 main.o -o test

Test drives:

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

See what happens? The srl instruction is shifting the sign bit

-2 = 0xfffffffe

if we shift one bit to the right, we get 0x7fffffff

0x7ffffffff = 2147483647

Of course this is not a problem when the number is a positive integer, because the sign bit is 0.

OTHER TIPS

To do unsigned integer division, thats right. This only works for unsigned integers and if you don't care about the fractional part.

You will want to use a shift amount of 1, not 2:

srl $t1, $t0, 1

If you use 2, you will end up dividing by 4. In general, shifting right by x divides by 2x.

If you are concerned about "rounding" and you want to round up, you can just increment by 1 before doing the logical (unsigned) shift.

And other have stated it previously but you only shift by 1 to divide by 2. A right shift by N bits divides by 2^N.

To use rounding (rounding up at 0.5 or greater) with shift values of N other than 1, just add 1<<(N-1) prior to the shift.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top