Умножение в MIPS

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

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

# program to multiply two 31 bit binary numbers (A & 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 (десятичный)


person rdopler    schedule 27.03.2019    source источник
comment
Ваш алгоритм кажется правильным, но когда вы умножаете два 32-битных числа, результат составляет 64 бита. Вы, вероятно, используете 32-битные мипы, и с вашим алгоритмом у вас есть арифметическое переполнение. Вы можете использовать $t3 для сохранения младшей битовой части результата, а в цикле вместо сдвига $t0 с шагом a/ сохранить младший бит $t2 в $t4 b/ srl $t2 $t2 1 и srl $t3,$t3,1 c/ повторно ввести младший бит $t4 в старшего разряда $t3, сдвинув его на 31 и объединив его с $t3.   -  person Alain Merigot    schedule 27.03.2019
comment
Я думал так же, как сохранить часть этого в $ t3, чтобы избежать ошибки. Я попытался реализовать то, что вы сказали, но я думаю, что изменяю не те части. Вы были чрезвычайно полезны до сих пор. Я уверен, что вы будете ненавидеть меня, но есть шанс, что вы можете изменить его на основе вашего комментария. Кажется, я неправильно его модифицирую. Прошу прощения, я новичок в ассемблере, и он все еще немного туманен, возможно, если бы я визуализировал ваш мыслительный процесс, это сделало бы его намного яснее для меня. Я буду очень признателен. Я очень хочу узнать, как работает этот процесс.   -  person rdopler    schedule 27.03.2019


Ответы (1)


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

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

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

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

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

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

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

# program to multiply two 31 bit binary numbers (A & 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
person Alain Merigot    schedule 27.03.2019
comment
Довольно часто нужны только младшие 32 бита продукта 32x32; предположительно, это то, что пытался реализовать ОП. Кстати, MIPS может переходить к знаковому биту регистра с помощью одной инструкции (bltz). Но у него нет команды поворота, так что это не помогает уменьшить накладные расходы AND/SLL, если только мы не начинаем с MSB (и считаем, что другое множимое начинается со сдвига влево на 32). Или, может быть, вы можете использовать сдвиг с переменным счетчиком, используя обратный счетчик в качестве счетчика смен. (Но тогда вы не можете отбросить его и выйти из цикла, когда вы сдвинули все биты из одного операнда.) - person Peter Cordes; 27.03.2019
comment
Я очень ценю помощь Питера. Комментарии к каждой строке кода творили чудеса с моим мыслительным процессом. Я не могу отблагодарить вас достаточно. Я чувствую себя намного лучше, сталкиваясь с проблемой таким образом. - person rdopler; 28.03.2019
comment
@rdopler: я только прокомментировал ответ Алена. Вы должны поблагодарить его, щелкнув галочку под стрелками вверх / вниз, чтобы отметить его как принятый, если вы считаете, что он достаточно отвечает на вопрос. - person Peter Cordes; 28.03.2019