我正在编写一个程序来添加两个双精度而不使用浮点寄存器。它现在有点工作,但有些数字给我错误的结果。例如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
答案 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语言或您喜欢的高级语言实现,然后只需要将其转换为汇编,如果需要汇编(这里是否需要汇编?)