2016-01-09 4 views
1

Я пишу программу для добавления двух двухместных номеров без использования регистров с плавающей запятой. Сейчас это работает, но некоторые цифры дают мне неправильные результаты. Например, 1 + 1 и 2.5 + 2.4 работают, но 1 + 2 дает мне 7 или 1001.5 + 8998.4 дает мне 26383.8999. Я думаю, что я определил проблему, а именно: После добавления чисел я сдвигаю (нормализую) результат, который должен быть только в том случае, если он находится в форме, например, 10.0110. Проблема заключается в том, что я не знаю, как проверить, равна ли сумма 10. (что-то) и продолжить нормализацию, или 1. (что-то) и перейти прямо к отображение результата. Я был бы очень доволен, если бы кто-то помог мне найти ответ или исправить мой код. EDIT: Итак, благодаря помощи мне удалось исправить проблемы с добавлением, но теперь я заметил проблемы с добавлением чисел с разными знаками. Ну, я сделал это, когда есть разные знаки, числа вычитаются. Он работает для целых чисел, а некоторые удваивает, но, например, 33,5 -23,2 приводит к 0.110110100110011 ... который нормализуется до 1.10110100110011 ... = 27,3, тогда как он должен быть 1.0110100110011 ... = 11.3 Обновленный код:MIPS Добавление двух чисел с плавающей запятой с двойной точностью без регистров с плавающей запятой

.data 
text1: .asciiz "Enter first double: " 
text2: .asciiz "Enter second double: " 
text3: .asciiz "Result: " 
quest: .asciiz "\nIf you want to continue enter 1, otherwise enter 0: " 
num1a: .word  0   # sign, exponent and part of the mantissa 
num1b: .word  0   # second part of the mantissa 
num2a: .word  0   # sign, exponent and part of the mantissa 
num2b: .word  0   # second part of the mantissa 
    .text 
    .globl input  
input: 
    #print "Enter first double: " 
    la $a0, text1 
    li $v0, 4 
    syscall 
    # saving input double into num1 
    li $v0, 7 
    syscall     
    swc1 $f0, num1b 
    swc1 $f1, num1a 
    #print "Enter second double: " 
    la $a0, text2 
    li $v0, 4 
    syscall 
    # saving input double into num2 
    li $v0, 7 
    syscall     
    swc1 $f0, num2b 
    swc1 $f1, num2a 

    # loading data to registers 
    lw $t0, num1a 
    lw $t1, num1b 
    lw $t2, num2a 
    lw $t3, num2b 


#########################################################sign 
sign:  
    move $t4, $t0 
    andi $t4, $t4, 0x80000000 #preserve sign, zero the rest 

    move $t5, $t2 
    andi $t5, $t5, 0x80000000 #preserve sign, zero the rest 

    bne  $t4, $t5, same 
    j  extract 

same: 
    bne  $t0, $t2, extract 
    beq  $t1, $t3, zero 

extract:  
################################################checking for zero 
    or $s2, $t0, $t1  #if both part of double are equal to zero we skip all the calculation 
    or $s3, $t2, $t3 
    beqz $s2, first_zero 
    beqz $s3, output 

###############################sign, exponent and mantissa 
    move $t6, $t0  
    andi $t6, $t6, 0x7FF00000 #extracting exponent to $t6 
    move $a0, $t6 

    move $t7, $t0 
    andi $t7, $t7, 0x000FFFFF #extracting first part of mantissa 
    ori  $t7, $t7, 0x00100000 #adding prefix one to mantissa 
    #remaining mantissa stays in register $t1 

    move $t8, $t2  
    andi $t8, $t8, 0x7FF00000 #extracting exponent to $t8 
    move $t9, $t2 
    andi $t9, $t9, 0x000FFFFF #extracting first part of mantissa 
    ori  $t9, $t9, 0x00100000 #adding prefix one to mantissa 
    #remaining mantissa stays in register $t3 

######################################################### 
exp_check: 
    #beq $t6, $t8, adding 
    bgt $t6, $t8, exp1 #exponent $t8 smaller than $t6 
    bgt $t8, $t6, exp2 

    bgt  $t4, $t5, sub_first 
    blt  $t4, $t5, sub_second 

add: 

    addu $t7, $t7, $t9 #add first parts of mantissas 
    addu $t1, $t1, $t3 #add the rest of the mantissas 

    move $s1, $t4  #move sign of the first double to $s1 

    j  shift 

sub_first: 
    bgt $t9, $t7, sub_second 
    bgt $t3, $t1, sub_second 

    subu $t7, $t7, $t9 #sub first parts of mantissas 
    subu $t1, $t1, $t3 #sub the rest of the mantissas 

    move $s1, $t4 

    j  shift2 

sub_second: 
    subu $t7, $t9, $t7 #sub first parts of mantissas 
    subu $t1, $t3, $t1 #sub the rest of the mantissas 

    move $s1, $t5  #move sign of the secon double to $s1 

    j  shift2 

exp1: 
    sll $s4, $t9, 31 #copy lsb of m1 
    sll $s5, $t3, 31 #copy lsb of m2 

    srl $t9, $t9, 1 #shift first part of the mantissa 
    srl $t3, $t3, 1 #shift the rest of the mantissa 

    or  $t9, $t9, $s4 #put lsb in m1 
    or  $t3, $t3, $s5 #put lsb in m2 

    addiu $t8, $t8, 0x00100000 #increase exponent $t8 

    j  exp_check 
exp2: 
    sll $s4, $t7, 31 #copy lsb of m1 
    sll $s5, $t1, 31 #copy lsb of m2 

    srl $t7, $t7, 1 #shift first part of the mantissa 
    srl $t1, $t1, 1 #shift the rest of the mantissa 

    or  $t7, $t7, $s4 #put lsb in m1 
    or  $t1, $t1, $s5 #put lsb in m2 

    addiu $t6, $t6, 0x00100000 #increase exponent $t6 

    j  exp_check 

shift: 

    #andi $t8, $t7, 0x80000000 
    #li $t4, 0 
    #bne $t8, $t4, result 

    andi  $t4, $t7, 0x00200000 
    beqz  $t4, result 

    sll $s2, $t7, 31 #copy least significant bit of m1 
    #sll $s3, $t1, 31 #copy lsb of m2 

    srl $t7, $t7, 1 #shift right m1 
    srl $t1, $t1, 1 #shift right m2 

    or  $t1, $t1, $s2 #put m1's lsb in m2 msb 
    #or  $t1, $t1, $s3 #put lsb in m2 

    add $t6, $t6, 0x00100000 #increase exp 
    j result 

shift2: 
    andi  $t4, $t7, 0x00100000 
    bnez  $t4, result 

    srl  $s3, $t1, 31 #copy most significant bit of m2 
    #sll $s2, $t7, 31 #copy most significant bit of m2 
    #sll $s3, $t1, 31 #copy lsb of m2 

    sll $t7, $t7, 1 #shift right m1 
    sll $t1, $t1, 1 #shift right m2 

    or  $t7, $t7, $s3 #put m2's msb in m1 lsb 
    #or  $t1, $t1, $s3 #put lsb in m2 

    sub $t6, $t6, 0x00100000 #increase exp 

result: 
    andi $t7, $t7, 0x000FFFFF #preserve mantissa, zero the rest(cut the prefix - one) 

    move $t0, $s1  #copy propoer sign 
    or  $t0, $t0, $t6  #add exponent 
    or  $t0, $t0, $t7  #add mantissa part1 
    b  output 

first_zero: 
    move $t0, $t2 
    move $t1, $t3 
    j  output 

zero: 
    li $t0, 0x00000000 
    li $t1, 0x00000000 

output: 
    sw $t0, num1a 
    sw $t1, num1b 
    #print "Result: " 
    la $a0, text3 
    li $v0, 4 
    syscall 
    lwc1 $f12, num1b 
    lwc1 $f13, num1a 
    #print double - the result 
    li $v0, 3 
    syscall 
question: 
    la $a0, quest   #Do you want to enter new numbers or finish? 
    li $v0, 4 
    syscall 
    li $v0, 5   #reads the answer (integer) 
    syscall 
    beq $v0, 1, input   #if input =1, continue, if 0 finish, otherwise ask again 
    beqz $v0, fin 
    b question 
fin: 
    li $v0, 10    #exit 
    syscall 
+0

Не уверен, что ваша проблема, вы можете просто сравнить мантиссы к эквивалент '10'. – Jester

+0

Добавление 1 + 1 дает 10.000 ... которое затем сдвигается на 1.0000 ..., но 1 + 2 дает 1.100 ... которое нельзя сдвинуть, потому что тогда я получаю 1.1100 ... = 7. Предполагаю, мне нужно найти способ выбрать, какие результаты сдвинуться, а какие нет. Вы имеете в виду сравнить первую часть мантиссы (первые 20 бит) с 10 или 11, и если они равны, то сдвиг, а если нет, то нет? – CybeQ

+0

Ну, у мантиссы 53 бит, и вам нужно сохранить это так. Итак, все, что вам нужно проверить, - это получить перенос, который делает его 54 бит. Вы можете сделать это с помощью простого поразрядного «и» или нормального сравнения. – Jester

ответ

1

Алгоритм должен быть таким образом:

Скажем, мы хотим добавить 1234 и 567, но сделать это с плавающей запятой. Для этого небинарного примера допустим, что у нас 1234 как 1.234 * 10^3 и 567 равно 5.67 * 10^2

10^3 является более крупным показателем, поэтому нам нужно выровнять десятичные знаки, поэтому мы сдвигаем меньшее число до десятичных линий до бита/номер на нижнем конце мантиссы для этого меньшего числа может упасть в конце концов, вы можете захотеть сохранить некоторые липкие биты или нет ...

1.23400*10^3 
+5.67000*10^2 
------------- 
1.23400*10^3 
+0.56700*10^3 
------------- 

так что теперь мы можем добавить

011000 
123400*10^3 
+056700*10^3 
------------ 
180100*10^3 

и это ответ 1.8100 * 10^3

что делать, если мы носили?

5678 + 9876

1 11000 
5.67800*10^3 
+9.87600*10^3 
============= 
15.55400*10^3 

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

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

15.55400*10^3 
&1110.00000 
=========== 
    1.55540*10^4 
&1110.00000 
=========== 

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

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

Я рекомендую реализацию в C или ваш любимый язык высокого уровня, то просто перевести, что в сборку, если требуется сборка (ли сборка здесь требуется?)

Смежные вопросы