MIPS添加两个没有浮点寄存器的双精度浮点数

时间:2016-01-09 23:41:03

标签: assembly double mips add

我正在编写一个程序来添加两个双精度而不使用浮点寄存器。它现在有点工作,但有些数字给我错误的结果。例如1 + 1和2.5 + 2.4工作,但1 + 2给我7,或1001.5 + 8998.4给我26383.8999我想我已经确定了问题,这是:添加数字后我移位(规范化)结果,这应该只是在它的形式,例如10.0110的情况下。问题是我不知道如何检查总和是否为10.(某事)并继续进行规范化,或1.(某事)并直接进入显示结果。如果有人可以帮我找到答案或更正我的代码,我会非常高兴。 编辑:所以,感谢我帮助我解决了添加的问题,但现在我注意到添加不同符号的数字有问题。好吧,我做到了这一点,当有不同的标志数字被减去。它适用于整数,有些加倍,但例如33.5 -23.2结果为0.110110100110011 ...标准化为1.10110100110011 ... = 27.3,而应该是1.0110100110011 ... = 11.3更新代码:

.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

1 个答案:

答案 0 :(得分: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语言或您喜欢的高级语言实现,然后只需要将其转换为汇编,如果需要汇编(这里是否需要汇编?)