装配Mips - 转换两个字符串(包含Float)并找到它们之间的间隙

时间:2016-11-29 20:11:44

标签: arrays assembly floating-point int mips

我必须创建一个函数来返回两个浮点数之间的差异。

示例:用户A的lat是22.00,而用户B的lat是20.00(或24.00),结果必须是2.00。

这是一个简单的减法呀......我找到了一种存储浮点数的方法,没有\ n和点,但我找不到在算术运算中使用数组的方法。这非常令人沮丧。

我希望有人帮助我

.data

dot: .asciiz "."
aCapo: .asciiz "\n"

A: .word    nome1, cognome1, lat1, long1
nome1: .asciiz "Paolo\n"
cognome1: .asciiz "Bonomi\n"
lat1: .asciiz "69.31\n"
long1: .asciiz "45.00\n"

B: .word    nome2, cognome2, lat2, long2
nome2: .asciiz "Xhoni\n"
cognome2: .asciiz "Lara\n"
lat2: .asciiz "40.02\n"
long2: .asciiz "90.00\n"

array: .space 256

.text
.globl main

main:

la $a1, A
la $a2, B

la $t8, array

lw $s1, 8($a1)
lb $t0, 0($s1)
sb $t0, 0($t8)
lb $t0, 1($s1)
sb $t0, 1($t8)
lb $t0, 3($s1)
sb $t0, 2($t8)
lb $t0, 4($s1) 
sb $t0, 3($t8)
编辑:我只是想办法做到这一点

这个功能效果很好,顺便说一下我知道它根本不起作用..有太多的冗余,但我没有那么多时间所以..非常感谢你的提示和帮助

diff_geo:

array: .word 1
array2: .word 1

risultatoLat: .word 1
empty: .word 1

risultatoLong: .word 1
empty2: .word 1

#
# this fuction takes two utentiR in $a1 and $a2
# and return the difference by  lat and long from the two user
#

try_lat:
lw $s1, 8($a1)  # put in s1 adress lat1
la $t8, array

lb $t0, 4($s1) #
sb $t0, 0($t8) # 
lb $t0, 3($s1) # 
sb $t0, 1($t8) # 
lb $t0, 1($s1) # 
sb $t0, 2($t8) # 
lb $t0, 0($s1) # 
sb $t0, 3($t8) # 
lw $s0, 0($t8) # put in s0 lat1 without "." and "\n"

lw $s2, 8($a2) # put in s2 address lat2 
la $t9, array2 #

lb $t0, 4($s2) #
sb $t0, 0($t9) # 
lb $t0, 3($s2) # 
sb $t0, 1($t9) # 
lb $t0, 1($s2) # 
sb $t0, 2($t9) # 
lb $t0, 0($s2) # 
sb $t0, 3($t9) # 
lw $s1, 0($t9)  # put in s1 lat2 without "." and "\n" 

blt $s0, $s1, switch_utenti     # if latA < latB goto switch
beq $s0, $s1, return_equal      # if latA = latB return "00.00"

j do_sub_lat    # else do sub 

return_equal:
la $a0, str_diffLat # stamp "Differenza Latitudine: "
li $v0, 4
syscall

la $a0, str_same # stamp "00.00\n"
li $v0, 4
syscall

j try_long # goto process long

switch_utenti:
move $a0, $a1
move $a1, $a2
move $a2, $a0

do_sub_lat:
lw $s1, 8($a1)          # put in s1 adress lat1
lw $s2, 8($a2)          # put in s2 adress lat2
lb $t0, 0($s1)          # load first number of lat1
lb $t1, 0($s2)          # load first number of lat2
sub $t2, $t0, $t1       # t2 = t0 - t1 (decimal)
lb $t0, 1($s1)          # load second number lat1
lb $t1, 1($s2)          # load second number lat2
bge $t0, $t1, jEDLat    # if (T0 >= T1) jump exception 
li $t7, 1               # load 1 in t7
li $t6, 9               # load 9 in t6
sub $t2, $t2, $t7       # sub 1 from first number of the result  
add $t0, $t0, $t6       # add 9 to t0
sub $t1, $t1, $t7       # sub 1 to t1 (i have to made this because if i try to ad 10 to t0, 10 will be like "a" no "10")        
jEDLat:
sub $t3, $t0, $t1       # T0 - T1 risultato DECIMALE in T3
lb $t0, 3($s1)          # carico secondo numero di A
lb $t1, 3($s2)          # carico secondo numero di B
bge $t0, $t1, jETLat    # if (T0 >= T1) salta eccezione 
li $t7, 1               # carico 1 in T7
li $t6, 9               # carico 10 in T6
sub $t3, $t3, $t7       
add $t0, $t0, $t6
sub $t1, $t1, $t7   
jETLat: 
sub $t4, $t0, $t1       # T0 - T1 risultato DECIMALE in T4
lb $t0, 4($s1)          # carico quarto numero di A
lb $t1, 4($s2)          # carico quarto numero di B 
bge $t0, $t1, jEQLat    # if (T0 >= T1) salta eccezione 
li $t7, 1               # carico 1 in T7
li $t6, 9               # carico 10 in T6
sub $t4, $t2, $t7       
add $t0, $t0, $t6       
sub $t1, $t1, $t7 
jEQLat:
sub $t5, $t0, $t1       # T0 -T1 risultato DECIMALE in T5

addi $t2, $t2, 48
addi $t3, $t3, 48
addi $t4, $t4, 48
addi $t5, $t5, 48


la $t8, risultatoLat
la $t7, aCapo
lb $t7, 0($t7)
sb $t7, 5($t8)
sb $t5, 4($t8)
sb $t4, 3($t8)
la $t7, dot
lb $t7, 0($t7)
sb $t7, 2($t8)
sb $t3, 1($t8)
sb $t2, 0($t8)


la $a0, str_diffLat
li $v0, 4
syscall

la $a0, risultatoLat
li $v0, 4
syscall

try_long:
lw $s1, 12($a1) # Metto in S1 la parola puntata da A1
la $t8, array

lb $t0, 4($s1) #
sb $t0, 0($t8) # 
lb $t0, 3($s1) # 
sb $t0, 1($t8) # 
lb $t0, 1($s1) # 
sb $t0, 2($t8) # 
lb $t0, 0($s1) # 
sb $t0, 3($t8) # 
lw $s0, 0($t8)  # IN S0 LONGITUDINE A

lw $s2, 12($a2) # Metto in S2 la parola puntata da A2 
la $t9, array2

lb $t0, 4($s2) #
sb $t0, 0($t9) # 
lb $t0, 3($s2) # 
sb $t0, 1($t9) # 
lb $t0, 1($s2) # 
sb $t0, 2($t9) # 
lb $t0, 0($s2) # 
sb $t0, 3($t9) # 
lw $s1, 0($t9)  # IN S1 LONGITUDINE B 

blt $s0, $s1, switch_utenti2    # se latA < latB inverto
beq $s0, $s1, return_equal2     # se latA = a latB ritorno 00.00    

j do_sub_long

return_equal2:
la $a0, str_diffLong # stampo "Differenza Longitudine: "
li $v0, 4
syscall

la $a0, str_same # stampo "00.00\n"
li $v0, 4
syscall

jr $ra # fine funzione

switch_utenti2:
move $a0, $a1
move $a1, $a2
move $a2, $a0

do_sub_long:
lw $s1, 12($a1)         # Metto in S1 la parola puntata da A1
lw $s2, 12($a2)         # Metto in S2 la parola puntata da A2 
lb $t0, 0($s1)          # carico primo numero di A
lb $t1, 0($s2)          # carico primo numero di B
sub $t2, $t0, $t1       # T0 - T2 risultato DECIMALE in T2
lb $t0, 1($s1)          # carico secondo numero di A
lb $t1, 1($s2)          # carico secondo numero di B
bge $t0, $t1, jEDLong   # if (T0 >= T1) salta eccezione 
li $t7, 1               # carico 1 in T7
li $t6, 9               # carico 10 in T6
sub $t2, $t2, $t7        
add $t0, $t0, $t6
sub $t1, $t1, $t7       
jEDLong:
sub $t3, $t0, $t1       # T0 - T1 risultato DECIMALE in T3
lb $t0, 3($s1)          # carico secondo numero di A
lb $t1, 3($s2)          # carico secondo numero di B
bge $t0, $t1, jETLong   # if (T0 >= T1) salta eccezione 
li $t7, 1               # carico 1 in T7
li $t6, 9               # carico 10 in T6
sub $t3, $t3, $t7       
add $t0, $t0, $t6
sub $t1, $t1, $t7   
jETLong:    
sub $t4, $t0, $t1       # T0 - T1 risultato DECIMALE in T4
lb $t0, 4($s1)          # carico quarto numero di A
lb $t1, 4($s2)          # carico quarto numero di B 
bge $t0, $t1, jEQLong   # if (T0 >= T1) salta eccezione 
li $t7, 1               # carico 1 in T7
li $t6, 9               # carico 10 in T6
sub $t4, $t2, $t7       
add $t0, $t0, $t6       
sub $t1, $t1, $t7 
jEQLong:
sub $t5, $t0, $t1       # T0 -T1 risultato DECIMALE in T5

addi $t2, $t2, 48
addi $t3, $t3, 48
addi $t4, $t4, 48
addi $t5, $t5, 48

la $t7, aCapo
lb $t7, 0($t7)
la $t8, risultatoLong
sb $t7, 5($t8)
sb $t5, 4($t8)
sb $t4, 3($t8)
la $t7, dot
lb $t7, 0($t7)
sb $t7, 2($t8)
sb $t3, 1($t8)
sb $t2, 0($t8)


la $a0, str_diffLong
li $v0, 4
syscall

la $a0, risultatoLong
li $v0, 4
syscall

la $a0, aCapo
li $v0, 4
syscall

jr $ra

我省略了lat和long格式对于所有

都是一样的

ctrl_geo:

#
# questa funzione prende come argomento in $a0 una indirizzo ad una stringa
# la funzione contolla se il formato è corretto cioè rispetta il formato "xx.xx\n" con x compreso tra 0 e 9
# restituisce in $a0 1 se l'inserimento è avvenuto correttamente altrimenti stampa a video una stringa di errore
# e restituisce in $a0 0
#

lb $t0, 0($a0) # carico numero decine in $t0
lb $t1, min
blt $t0, $t1, errore_geo # controllo se è minore di 0
lb $t1, max
bgt $t0, $t1, errore_geo # controllo se è maggiore di 9

lb $t0, 1($a0) # carico numero unità in $t0
lb $t1, min
blt $t0, $t1, errore_geo # controllo se è minore di 0
lb $t1, max
bgt $t0, $t1, errore_geo # controllo se è maggiore di 9

lb $t0, 2($a0) # carico punto in $t0
lb $t1, dot
bne $t0, $t1, errore_geo # se non c'è un punto in t0 mando ad errore

lb $t0, 3($a0) # carico numero dopo punto decine in $t0
lb $t1, min
blt $t0, $t1, errore_geo # controllo se è minore di 0
lb $t1, max
bgt $t0, $t1, errore_geo # controllo se è maggiore di 9

lb $t0, 4($a0) # carico numero dopo punto unità in $t0
lb $t1, min
blt $t0, $t1, errore_geo # controllo se è minore di 0
lb $t1, max
bgt $t0, $t1, errore_geo # controllo se è maggiore di 9

lb $t0, 5($a0) # a capo in $t0
lb $t1, aCapo
bne $t0, $t1, errore_geo # se in t0 non ho aCAPO mando a errore 

li $a0, 1
jr $ra # fine funzione

errore_geo:
la $a0, str_erroreNumerico
li $v0, 4
syscall

li $a0, 0
jr $ra # fine funzione 

这是如此不起作用我知道...也许如果我存储lat和long值像浮动而不像ascii那样可以避免很多麻烦。

1 个答案:

答案 0 :(得分:1)

我不确定你的意思:

  

无法在算术运算中找到使用数组的方法

就像在汇编中那样,甚至没有一个像#34; array&#34;这样的明确定义的东西,但你可能意味着一定数量的连续字节。

sub之类的算术指令只能用于寄存器(并且只能用于字大小)。

所以如果你有两个ASCII&#34;数字&#34;在带有删除小数点和换行符的字符串中,如:

num1: .byte '1', '2', '7', '8', 0  # was "12.78\n"
num2: .byte '5', '6', '3', '4', 0  # was "56.34\n"
res:  .space 16  # should be plenty for lat/lon difference

获取n1i = 3, n2i = 3的最后一位数字索引并设置resi = max(n1i, n2i)

现在你想要sub的绝对值,你可以检查哪个数字更小,然后从更大的数字中减去那个。

num1bigger = (n2i < n1i) || (n1i == n2i && first_different_digit_is_bigger_in_n1);
// equal numbers will produce "false"

编辑:实际上,这会对一个特殊情况产生错误结果num1 = "0012" vs num2 = "345"会产生num1bigger = true;,只有当前导零不是考虑的ASCII数字的一部分时,描述的东西才有效。

这很好(以无计划的方式)说明了为什么你应该用尽可能多的极端情况对你的算法进行单元测试(包括像空数据和空数据这样的东西,如果适用的话),以及甚至&#34;琐碎&#34;任务可以很容易地编码错误。好吧,不仅仅是编码,而且已经设计并且在高级别上存在错误。

现在减法算法(用C语言伪语言,如果你不知道C,那么抱歉):

    init:
      already set: n1i, n2i, num1bigger, num1, num2, res, resi
      borrow = false, res[resi+1] = 0

    sub_loop:
  *1  r1 = (0 <= n1i) ? num1[n1i--] : '0'
      r2 = (0 <= n2i) ? num1[n2i--] : '0'
      if (!num1bigger) swap(r1,r2)
      // r1 is byte-part of bigger number, r2 of smaller
      if (borrow) ++r2
  *2  r3 = r1 - r2       // ASCII - ASCII = numeric value
      borrow = (r3 < 0)
      if (borrow) r3 += 10  // adjust negative into 0-9
      r3 += '0'          // add ASCII encoding back
  *3  res[resi--] = r3
      if (0 <= resi) jump sub_loop
      // as the smaller number is subtracted from larger, borrow=0 at end
      // so no need to patch the result in sign flip way

      // but you may want to remove leading zeroes
      // (but keep at least three of them for "0.00" result) 

这是每字节ASCII绝对值减法算法。 (输入[22,20]和[22,24]都会产生+02结果!)。

BTW,对于非绝对减法,它实际上几乎相同,但是当!num1bigger时,必须在结果之前添加减号=&gt; 22-24 = -02(现在领先的零看起来很糟糕:))。

对于我的示例数组,循环内部的值将类似于:

init:
num1bigger = false, borrow = false, res[4] = 0
  Loop first iteration:
  *1 fetching, swapping, borrow adjust: r1 = '4', r2 = '8'
  *2 subtraction, adjustment: r3 = '6', borrow = true
  *3 store result: res[3] = '6', n1i == n2i == resi == 2
  (0 <= resi (2)) -> loop again
  *1 fetching, swapping, borrow adjust: r1 = '3', r2 = '8'
  *2 subtraction, adjustment: r3 = '5', borrow = true
  *3 store result: res[2] = '5', n1i == n2i == resi == 1
  (0 <= resi (1)) -> loop again
  *1 fetching, swapping, borrow adjust: r1 = '6', r2 = '3'
  *2 subtraction, adjustment: r3 = '3', borrow = false
  *3 store result: res[1] = '3', n1i == n2i == resi == 0
  (0 <= resi (0)) -> loop again
  *1 fetching, swapping, borrow adjust: r1 = '5', r2 = '1'
  *2 subtraction, adjustment: r3 = '4', borrow = false
  *3 store result: res[0] = '4', n1i == n2i == resi == -1
  !(0 <= resi (-1)) -> exit loop
  // here res bytes are set to '4', '3', '5', '6', 0
  // which can be formatted as result 43.56 (== 56.34 - 12.78)

...我不会尝试用MIPS汇编来编写它,因为我从来没有在其中编码,而且我无法从你那里窃取所有乐趣。我希望上面给出了你的想法,你如何在ASCIIZ数字字符串上进行算术运算。

基本上你应该把它写在纸上,并集中在你只能按步骤操作单个数字时你会做什么。并将其作为算法写下来。

尝试几个值(确保有一些极端情况,例如我的&#34; first_different_digit_is_bigger_in_n1&#34;或两个相等的值,或123.45 - 7.890.00输入甚至可能为空字符串)。

如果它看起来很稳定,只需在这些步骤之间写下指令(我试图将我的算法分解为许多简单的小步骤,其中大多数应该最多通过1-2条指令解决,有时可能会3-4当我错过了MIPS架构时,我已经习惯了x86指令,所以我尝试遵循更多类似RISC的逻辑(例如避免使用标志),但仍然......)。