Умножение в MIPS путем сдвига и сложения, без mult

#assembly #mips #mars-simulator

#сборка #mips #mars-симулятор

Вопрос:

У меня есть следующий код, но я продолжаю получать ошибку арифметического переполнения. Проблема, которую я пытаюсь решить, заключается в умножении двух 31-разрядных чисел вместе и сохранении результатов в $ t2 $ t3 и распечатке правильного результата. Кажется, что я закодировал для умножения два числа, и конечным результатом является 31-битное число.

Я бы хотел сузить область, где, как мне кажется, я ошибаюсь, но, честно говоря, я не вижу, где и что мне нужно изменить.

 # program to multiply two 31 bit binary numbers (A amp; B),

# using the “shift and add” .

.data

# declare the variable lables of ASCII storage type.

prompt1: .asciiz "Enter number 1: "

prompt2: .asciiz "Enter number 2: "

result: .asciiz "The multiplication of two 31 bit binary numbers is: "

.text
  

Главная:

             #prompt1.

            li $v0, 4   

            la $a0, prompt1

            syscall

           #read number 1 and store in the register $t0

            li $v0, 5        

            syscall  

            move $t0, $v0

         

            #prompt2.

            li $v0, 4   

            la $a0, prompt2

            syscall

           

            #read number 2 and store in the register $t1

            li $v0, 5        

            syscall  

            move $t1, $v0

                          

            li $t2, 0 # The final result of the multiplication

                            #is saved into the register $t2

            li $t3, 1 # Mask for extracting bit!

            li $s1, 0 # set the Counter to 0 for loop.   
  

умножение:

             #if the Counter $s1 is equal to 31, then go the lable exit

            beq $s1, 31, exit

            and $s2, $t1, $t3

            sll $t3, $t3, 1

                    beq $s2, 0, increment

            add $t2, $t2, $t0
  

увеличение:

             sll $t0, $t0, 1

            addi $s1, $s1, 1

            j multiply
  

выход:

             #display the result string.

            li $v0, 4   

            la $a0, result

            syscall

                            #display the result value.

            li $v0, 1

            add $a0, $t2, $zero

            syscall

         

            li $v0, 10 # system call code for exit = 10

            syscall   # call operating sys
  

Пример ввода A: 1143330295 (десятичный)
Пример ввода B: 999999223 (десятичный)

Комментарии:

1. Ваш алгоритм кажется правильным, но когда вы умножаете два 32-битных числа, результат равен 64 битам. Вероятно, вы используете 32-битный mips, и в вашем алгоритме происходит арифметическое переполнение. Вы можете использовать $ t3 для сохранения lsb-части результата, и в цикле вместо того, чтобы сдвигать $ t0 с приращением, a / сохранить lsb из $ t2 в $ t4 b / srl $t2 $t2 1 и srl $t3,$t3,1 c / повторно ввести lsb из $ t4 в msb из $ t3, сдвинув его на 31 и заменив на $ t3.

2. Я подумал о том же, что и о сохранении его части в $ t3, чтобы избежать ошибки. Я пытался реализовать то, что вы сказали, но я думаю, что я изменяю неправильные части. До сих пор вы были чрезвычайно полезны. Я уверен, что вы меня возненавидите, но есть ли шанс, что вы могли бы изменить это на основе вашего комментария. Кажется, я изменяю это неправильно. Прошу прощения, я новичок в сборке, и она все еще немного туманна, возможно, если бы я визуализировал ваш мыслительный процесс, это сделало бы его для меня намного понятнее. Я был бы очень признателен за это. Я действительно хочу узнать, как работает этот процесс.

Ответ №1:

Вот возможная реализация.

Отличия от вашего кода :

  • умножение 32×32 генерирует 64-битный результат. В 32-битном mips результат должен быть разделен на два регистра

  • вместо сдвигающего влево операнда, что приведет к переполнениям, результат сдвигается вправо. Удаленные биты сохраняются и повторно вводятся в нижнюю часть результата

  • используйте addu для сложения. Числа без знака и без операций без знака могут возникать переполнения

  • изменен цикл в форме «делать во время». Счетчик циклов уменьшается

Отображаемый результат в настоящее время состоит из двух частей. Неправильное отображение может произойти, если установлен LSB (и считается отрицательным знаком при системном вызове display int)), но в большинстве симуляторов mips нет способа отображать большое значение без знака.

 # program to multiply two 31 bit binary numbers (A amp; B),
# using the “shift and add” .

.data
# declare the variable lables of ASCII storage type.
prompt1: .asciiz "Enter number 1: "
prompt2: .asciiz "Enter number 2: "
result: .asciiz "The multiplication of two 31 bit binary numbers is: "
result2: .asciiz "nand the upper part of result is: "

.text
main:
        #prompt1.
        li $v0, 4   
        la $a0, prompt1
        syscall

        #read number 1 and store in the register $t0
        li $v0, 5        
        syscall  
        move $t0, $v0

        #prompt2.
        li $v0, 4   
        la $a0, prompt2
        syscall

        #read number 2 and store in the register $t1
        li $v0, 5        
        syscall  
        move $t1, $v0

        li $t2, 0 # The final result of the multiplication is 64 bits
                  # MSB part is in register $t2
        li $t4, 0 #  and LSB part of result is in $t4
        li $t3, 1 # Mask for extracting bit!
        li $s1, 32 # set the Counter to 32 for loop.   

multiply:
        and $s2, $t1, $t3
        beq $s2, 0, increment
        addu $t2, $t2, $t0

increment:
        sll $t3, $t3, 1 # update mask
        ##sll $t0, $t0, 1 # useless, we srl result instead
        andi $s4, $t2,1  # save lsb of result
        srl $t2,$t2,1    # t2>>=1
        srl $t4,$t4,1    # t4>>=1
        sll $s4,$s4,31
        or  $t4,$t4,$s4  # reinject saved lsb of result in msb of $t4
        addi $s1, $s1, -1 # decrement loop counter
        #if the Counter $s1 reaches 0 then go the label exit
        beq $s1, $zero, exit
        j multiply

exit:
        #display the result string.
        ## must be changed to take into account the 64 bits of the result
        ## but AFAIK, there is no syscall for that
        ## can be done in two steps t4 and t2
        ## and result is t4 2**32*t2
        #display the result value.
        li $v0, 4   
        la $a0, result
        syscall
        li $v0, 1  # if using mars replace 1 by 36 to print as an unsigned
        add $a0, $t4, $zero
        syscall
        li $v0, 4   
        la $a0, result2
        syscall
        li $v0, 1 # if using mars replace 1 by 36 to print as an unsigned
        add $a0, $t2, $zero
        syscall

        li $v0, 10 # system call code for exit = 10
        syscall   # call operating sys
  

Комментарии:

1. Довольно часто требуется только младшие 32 бита продукта 32×32; предположительно, это то, что пыталась реализовать операционная система. И, кстати, MIPS может разветвляться на знаковый бит регистра с помощью одной инструкции ( bltz ). Но в нем нет инструкции rotate, так что это не помогает уменьшить накладные расходы и / SLL, если мы не начнем с MSB (и рассмотрим другой множитель, который начинается со сдвига влево на 32). Или, может быть, вы можете использовать сдвиг с переменным числом, используя счетчик уменьшения в качестве счетчика сдвига. (Но тогда вы не сможете отбросить это и выйти из цикла, когда вы сместили все биты из одного операнда.)

2. Я очень ценю помощь Питера. Комментарии к каждой строке кода сотворили чудеса с моим мыслительным процессом. Не знаю, как вас отблагодарить. Я чувствую себя намного лучше, решая проблему таким образом.

3. @rdopler: Я только прокомментировал ответ Алена. Вы должны поблагодарить его, нажав на галочку под стрелками голосования вверх / вниз, чтобы отметить это как «принято», если вы считаете, что это достаточно отвечает на вопрос.