Assembly Mips - 转换两个字符串(包含浮点数)并找到它们之间的间隙

Assembly Mips - convert two Strings (containing Float) and find the Gap between them

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

示例:用户 A 的纬度为 22.00,用户 B 的纬度为 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

我已经忽略了纬度和经度格式对所有人都相同

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 

这太不实用了,我知道...也许如果我像 float 而不是像 ascii 那样存储纬度和经度值,那会避免很多麻烦。

我不确定你的意思:

can't find a way to use the array in an arithmetical operation

在 Assembly 中甚至没有像 "array" 这样定义明确的东西,但你可能指的是一些连续的字节。

sub 这样的算术指令只能在寄存器上工作(并且只能使用字长)。

因此,如果字符串中有两个 ASCII "numbers",删除了小数点和换行符,例如:

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 数字的一部分时,所描述的内容才有效。

这很好地(以计划外的方式)说明了为什么您应该使用尽可能多的角落案例对您的算法进行单元测试(包括空数据和空数据,如果适用),以及 "trivial" 任务可以很容易地用错误编码。好吧,不仅是编码,而且已经设计,但存在高级别错误。


现在减法算法(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 结果!)。

顺便说一句,对于非绝对减法它实际上几乎相同,但是当!num1bigger时,必须在结果之前添加减号=> 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 数字字符串进行算术运算。

基本上你应该把它写在纸上,并专注于当你每一步只能操作一个数字时你会做什么。并将其记为算法。

在几个值上尝试(确保有一些极端情况,比如我的 "first_different_digit_is_bigger_in_n1",或两个相等的值,或 123.45 - 7.890.00 输入,甚至可能是空字符串).

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