В MIPS, как мне разделить содержимое регистра на два?

StackOverflow https://stackoverflow.com/questions/1569870

  •  21-09-2019
  •  | 
  •  

Вопрос

Допустим, у меня есть $t0, и я хотел бы разделить его целочисленное содержимое на два и сохранить его в $t1.

Мое чутье подсказывает: srl $t1, $t0, 2

...но разве это не было бы проблемой, если бы...скажи...самый правый бит был равен 1?Или все это выходит при стирке, потому что самый правый бит (если положительный) делает $t0 нечетное число, которое становится четным при делении?

Научите меня, о мудрейшие...

Это было полезно?

Решение

Используйте инструкцию sra:Сдвиньте правильную арифметику !!

sra $t1, $t0, 1

Делит содержимое $ t0 на первую степень 2.

Описание:Сдвигает значение регистра прямо на величину сдвига (shamt) и помещает значение в пункт назначения регистр.Знаковый бит сдвинут внутрь.

Операция:$d = $t >> h;

продвинутый пк (4);

Синтаксис:sra $d, $t, h

Кодирование:0000 00-- ---t tttt dddd dhhh hh00 0011

Почему это так важно?Проверьте эту простую программу, которая делит целое число (входные данные программы) на 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

Скомпилировать

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

Тест - драйвы:

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

Видите, что происходит?В srl инструкция заключается в сдвиге знакового бита

-2 = 0xfffffffe

если мы сдвинем один бит вправо, то получим 0x7fffffff

0x7ffffffff = 2147483647

Конечно, это не проблема, когда число является положительным целым числом, потому что знаковый бит равен 0.

Другие советы

Чтобы выполнить целочисленное деление без знака, это верно.Это работает только для целых чисел без знака, и если вас не волнует дробная часть.

Вы захотите использовать величину сдвига, равную 1, а не 2:

srl $t1, $t0, 1

Если вы используете 2, то в конечном итоге вы разделите на 4.В общем, смещение вправо по x делится на 2x.

Если вас беспокоит "округление" и вы хотите округлить, вы можете просто увеличить значение на 1, прежде чем выполнять логический (беззнаковый) сдвиг.

И другие заявляли об этом ранее, но вы сдвигаете только на 1, чтобы разделить на 2.Сдвиг вправо на N бит делит на 2^ N.

Чтобы использовать округление (округление в большую сторону на 0,5 или больше) со значениями сдвига N, отличными от 1, просто добавьте 1<<(N-1) до начала смены.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top