The user enters floating point values and they are saved on the stack, then printed out in the opposite order. If the user enters something less or equal to 1, it should skip the value. This does not work though. Why?
.data
strN: .asciiz "n=? \n"
strEingabe: .asciiz "te Zahl = ? \n"
strAusgabe: .asciiz "te Zahl = \n"
strNewLine: .asciiz "\n"
strNegative: .asciiz "\n Fehler: Ungültiger Wert für n!\n"
.text
.globl main
main:
li $v0, 4
la $a0, strN
syscall
li $v0, 5
syscall
move $s0, $v0 # $s0 = n
li $v0, 4
la $a0, strNewLine
syscall
bgtz $s0, input_loop_init
j negative
input_loop_init:
li $s1, 1
j input_loop
input_loop:
li $v0, 1
move $a0, $s1
syscall
li $v0, 4
la $a0, strEingabe
syscall
li $v0, 6 #read float, save in $f0
syscall
mfc1 $t0, $f0
bgt $t0, 1, input_loop1
j input_loop
input_loop1:
addi $sp, $sp, -4
sw $t0, 0($sp)
li $v0, 4
la $a0, strNewLine
syscall
addiu $s1, $s1, 1
ble $s1, $s0, input_loop
j output_loop_init
output_loop_init:
move $s1, $s0
j output_loop
output_loop:
li $v0, 1
move $a0, $s1
syscall
li $v0, 4
la $a0, strAusgabe
syscall
lw $a0, 0($sp)
mtc1 $a0, $f12
addi $sp, $sp, 4
li $v0, 2
syscall
li $v0, 4
la $a0, strNewLine
syscall
addi $s1, $s1, -1
bgt $s1, $zero, output_loop
j exit
negative:
li $v0, 4
la $a0, strNegative
syscall
j exit
exit:
li $v0, 10
syscall
I tried using things like cvt.s.w but i do not fully understand what it does yet. Whatever i did, it either said "operand of incorrect type" or it just returned everything the user entered, no matter what value (unless he entered something less than 0!)
CodePudding user response:
Processors rarely provide an approach to arithmetic (like comparison) of two different data types directly; usually arithmetic operations take two operands of the same type — so compare integer to integer or float to float is possible but not float to integer (not directly).
So, you will need to decide whether you want to convert the float to integer and then compare as integers, or convert the 1 to float, and then compare as float.
The former (convert float to int for int-to-int compare) will be lossy as the conversion to integer will loose all the decimal places.
Whereas the latter (convert int to float for float-to-float compare) can also be problematic since float computations don't always result in the same bit pattern — however, comparing with 1 (1.0) with little arithmetic should be ok. Problems can occur if you do, for example, (1.0/3.0)*3.0 — it may print out as 1.0 but not be the same exact bit pattern as another 1.0 so won't compare for equality! (Experts with floating point know to avoid equality comparisons and design their algorithms differently.)
You also need to know how the registers work. The registers hold bit patterns — transferring register's values from/to memory or from int regs to float regs or float to int does not change the bit pattern. Only explicit conversions and arithmetic change the bit patterns. The processor assumes that the instructions being used are a match with the bit patterns given in the registers.
So, moving a float to an integer register copies the bit pattern as is, without conversion to integer (and vice versa, copy an int to float register, the number is not yet in floating point format).
The conversions, e.g. cvt.s.w
between int and float, take place entirely within the floating point register set. The integer registers have no instructions for floating point format other than to copy as is.
To convert a float to int for comparison with an int using the integer registers, first convert from float to int in the floating registers, then copy to an integer register and use normal (integer) beq
& bne
, for example.
To convert a 1 from int to float, load 1 into integer register, then copy from integer register to float register, then convert to float in float registers. Finally a compare of float to float, setting the floating point condition code, which you can test with bc1f
and bc1t
.
An alternative, often chosen, is to place a constant float value in memory directly as in OneF: .float 1.0
. This will avoid the runtime conversion from int, and of course, since it is in memory you'll have to load it into a float register from memory (using l.s
(my preference) or lwc1
, which is the same).
If you should ever choose to experiment with substituting double for float, then I'd suggest sticking with the even float register numbers, as that will somewhat simplify.