Пользователь вводит значения с плавающей запятой, и они сохраняются в стеке, а затем распечатываются в обратном порядке. Если пользователь вводит что-то меньшее или равное 1, он должен пропустить это значение. Однако это не работает. Почему?
.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
Я пытался использовать такие вещи, как cvt.s.w, но я еще не до конца понимаю, что он делает. Что бы я ни делал, он либо сказал «операнд неправильного типа», либо просто вернул все, что ввел пользователь, независимо от того, какое значение (если только он не ввел что-то меньше 0!)
Процессоры редко предоставляют подход к арифметическим операциям (например, к сравнению) двух разных типов данных напрямую; обычно арифметические операции берут два операнда одного и того же типа, поэтому сравнение целого числа с целым числом или число с плавающей запятой возможно, но не число с плавающей запятой с целым числом (не напрямую).
Итак, вам нужно будет решить, хотите ли вы преобразовать число с плавающей запятой в целое число, а затем сравнить как целые числа, или преобразовать 1 в число с плавающей запятой, а затем сравнить как число с плавающей запятой.
Первый (преобразовать float в int для сравнения int-to-int) будет с потерями, так как преобразование в целое число потеряет все десятичные разряды.
Принимая во внимание, что последнее (преобразование int в число с плавающей запятой для сравнения с плавающей запятой) также может быть проблематичным, поскольку вычисления с плавающей запятой не всегда приводят к одному и тому же битовому шаблону, однако сравнение с 1 (1.0) с небольшими арифметическими действиями должно быть в порядке. Проблемы могут возникнуть, если вы сделаете, например, (1.0/3.0)*3.0 — это может быть распечатано как 1.0, но не будет точно таким же битовым шаблоном, как другой 1.0, поэтому сравнение не будет на равенство! (Эксперты по плавающей запятой знают, что следует избегать сравнений на равенство и разрабатывать свои алгоритмы по-другому.)
Вы также должны знать, как работают регистры. Регистры содержат битовые шаблоны — перенос значений регистра из/в память или из регистров int в регистры с плавающей запятой или с плавающей запятой в int не меняет битовый шаблон. Только явные преобразования и арифметические действия изменяют битовые комбинации. Процессор предполагает, что используемые инструкции совпадают с битовыми шаблонами, заданными в регистрах.
Таким образом, перемещение числа с плавающей запятой в целочисленный регистр копирует битовый шаблон как есть, без преобразования в целое число (и наоборот, копирование int в регистр с плавающей запятой, число еще не в формате с плавающей запятой).
Преобразования, например. cvt.s.w
между int и float полностью выполняются в наборе регистров с плавающей запятой. Целочисленные регистры не имеют никаких инструкций для формата с плавающей запятой, кроме как копировать как есть.
Чтобы преобразовать число с плавающей точкой в целое для сравнения с целым числом с помощью регистров целых чисел, сначала преобразуйте число с плавающей запятой в число целых чисел в регистрах с плавающей запятой, затем скопируйте в регистр целых чисел и используйте, например, обычные (целые) beq
и bne
.
Чтобы преобразовать 1 из int в число с плавающей запятой, загрузите 1 в целочисленный регистр, затем скопируйте из целочисленного регистра в регистр с плавающей запятой, а затем преобразуйте в число с плавающей запятой в регистрах с плавающей запятой. Наконец, сравнение float с float, установка кода условия с плавающей запятой, который вы можете проверить с помощью bc1f
и bc1t
.
Альтернативой, часто выбираемой, является размещение постоянного значения с плавающей запятой непосредственно в памяти, как в OneF: .float 1.0
. Это позволит избежать преобразования во время выполнения из int, и, конечно, поскольку он находится в памяти, вам придется загрузить его в регистр с плавающей запятой из памяти (используя l.s
(мое предпочтение) или lwc1
, что то же самое).
Если вы когда-нибудь решите поэкспериментировать с заменой числа с плавающей запятой на двойное, то я бы посоветовал придерживаться четных номеров регистров с плавающей запятой, так как это несколько упростит.
Спасибо, теперь моя программа печатает 0,0, когда я ввожу что-то меньше 1. Все еще нужно выяснить, как заставить мою программу избегать сохранения значений в стеке, когда это так.