2016-11-29 40 views
1

我必須創建一個返回兩個浮點數之間差異的函數。Assembly 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和長格式是所有

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和長值一樣浮動,而不是像ascii,這將防止很大的麻煩。

+0

祝你好運找到一個真正會花時間爲你寫的人。你在Assembly中問的很多!我不再記得這門語言,或者我會嘗試。 – Sethmr

+1

您是否必須將緯度和長度值存儲爲ascii?如果你可以將它們作爲浮點數存儲,這將會容易得多。 – Tim

+0

@Tim如果他沒有字符串到浮點數的轉換,可能會更容易將它們作爲字符串...:D ...或將它們轉換爲整數,如果他知道總是隻有2個十進制數地方,他可以使用100 *整數的所有內容,並在最後兩位數字之前用「'。'」輸出。 (我有點不知道,在那裏我會開始寫ascii - > float convertor,可能通過使用C++來實現,這是一塊詭code的代碼)。 – Ped7g

回答

1

我不知道你的意思:

不能找到一種方法來使用數組在大會算數運算

由於存在甚至不是一個喜歡明確的東西「數組」,但你可能意味着一定數量的連續字節。

sub算術指令只能工作在寄存器(只有用字的大小)。

所以,如果你已經在字符串中兩個ASCII「數字」去掉小數點點和換行,如:

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)

現在,只要你想子的絕對值,可以查看哪個數較小,減去更大一說一。

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碼的部分所描述的事情才起作用。

這很好(以非計劃的方式)說明了爲什麼你應該用盡可能多的角落案例對你的算法進行單元測試(包括諸如空數據和空數據之類的東西,如果適用的話)以及甚至「微不足道」任務可以用錯誤輕鬆編碼。那麼,不只是編碼,但已經設計了與高水平的錯誤。


現在減法算法(在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條指令解決, 4我錯過了MIPS架構太多了,我習慣x86指令,所以我試圖遵循更多類似RISC的邏輯(例如避免使用標誌),但仍然......)。

+0

此外,這應該很容易擴展以處理點「。」字符(它應該同時在'num1/num2'中遇到,並且只複製到'res'中,跳過減法並繼續循環) 。可能比從輸入中刪除它容易。 ''\ n''也是一樣,你可以將它們保存在那裏,當加載'\ n'時,只需在下一次循環迭代時跳轉。如果需要,甚至可以複製結果。 – Ped7g

相關問題