Assembly 添加两个不带浮点寄存器的双精度浮点数的MIPS
我正在编写一个程序,在不使用浮点寄存器的情况下添加两个double。这是一种工作现在,但一些数字给我错误的结果。例如,1+1和2.5+2.4都有效,但1+2给了我7,或者1001.5+8998.4给了我26383.8999,我想我已经确定了问题,那就是:在添加数字后,我移动(标准化)结果,这只应该是在形式中的情况,例如10.0110。问题是我不知道如何检查总和是否为10。(某些东西)然后继续标准化,或1.(某物),然后直接显示结果。如果有人能帮我找到答案或更正代码,我将非常感激。 编辑:多亏了帮助,我成功地解决了加法的问题,但现在我注意到了用不同符号添加数字的问题。当有不同的符号数字被减除时,我就这样做了。它适用于整数和一些双倍数,但例如33.5-23.2的结果是0.110100110011。。。标准化为1.10110100110011…=27.3,而它应该是1.01100110011…=11.3更新代码:Assembly 添加两个不带浮点寄存器的双精度浮点数的MIPS,assembly,double,mips,add,Assembly,Double,Mips,Add,我正在编写一个程序,在不使用浮点寄存器的情况下添加两个double。这是一种工作现在,但一些数字给我错误的结果。例如,1+1和2.5+2.4都有效,但1+2给了我7,或者1001.5+8998.4给了我26383.8999,我想我已经确定了问题,那就是:在添加数字后,我移动(标准化)结果,这只应该是在形式中的情况,例如10.0110。问题是我不知道如何检查总和是否为10。(某些东西)然后继续标准化,或1.(某物),然后直接显示结果。如果有人能帮我找到答案或更正代码,我将非常感激。 编辑:多亏了帮
.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
算法应遵循以下原则: 假设我们想添加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
我们知道变量的大小,它们比尾数大一点(或者尾数被分成几个部分,这样我们就可以有一些执行的空间,在操作之间级联)
在二进制和十进制之间混合数据流,但如果在小数点上加1、2,在小数点上加0,则在小数点右侧加0。如果这不是零,那么右移一,从尾数的右端抛出位
15.55400*10^3
&1110.00000
===========
1.55540*10^4
&1110.00000
===========
现在它已经正常化了。在循环中执行不一定有效。对于直接正数加法,在最坏的情况下,只能有一个额外的位移位。所以你只需要检查一位的位置,如果零,没有移位。但对于负数的减法或加法,则从小数点上方的一堆非零位开始,而不仅仅是一位。你可能需要向左或向右移动,所以你必须搜索第一个非零数(这取决于搜索结果是正的还是负的,假设是正的),你可能需要向左或向右移动,每次移动减少指数,向右增加指数。当然,先做一个零检查
不是说你还不知道,我没有仔细阅读你的代码。但是如果你遵循一个通用算法,那么它就会起作用,例如,当你自己加上一个正数时,那么任何两个正数都会起作用
我建议用C语言或您最喜欢的高级语言实现,然后如果需要汇编(这里需要汇编吗?不确定您的问题是什么,您可以简单地将尾数与
10
的等效值进行比较。添加1+1得到10.000。。。然后移到1.0000…,但1+2等于1.100。。。不能移动,因为我得到1.1100…=7.我想我需要找到方法来选择哪些结果需要改变,哪些不需要。你的意思是将尾数的第一部分(前20位)与10或11进行比较,如果它们相等,则移位,如果不相等,则不移位?尾数有53位,你需要保持这种方式。所以你需要测试的就是你是否得到一个54位的进位。你可以通过一个简单的按位和或者一个普通的比较来实现这一点。不是1位表示符号,11位表示指数,52位表示尾数吗?或者说是1。一开始也算吗?它存储在两个32位寄存器中,所以它被分成20位和32位两部分。仅检查前20位部分是否足够?所以我应该在尾数和寄存器之间使用按位的and,21位为1,如果它是1,那么将它移位?好的,这就行了。我在结果的尾数和0x00100000之间使用“andi”(这里是1.应该是),如果是1,则显示结果,如果不是1,则移动尾数。谢谢你,杰斯特。