Procedure annidate

di il
18 risposte

Procedure annidate

Utilizzando QtSpim, scrivere un programma che legga due interi non negativi x e y e visualizzi su console il loro prodotto prod(x,y) = { 0 se y=0 oppure somma(x,prod(x,y-1)) }
somma(x,y)= { x se y=0 oppure [1+ somma(x,y-1)] }

#Es_2 (procedura prod sum)
.data
risultato: .asciiz "\n ecco il risultato : "
inserisci1: .asciiz "\n Inserire il primo numero numero x : "
inserisci2: .asciiz "\n Inserire il secondo numero numero y : "
.text
.globl main


prod:
sub $sp, $sp,12 #si crea l'area di memoria per la procedura
sw $a0, 4($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
sw $a1, 8($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
sw $ra, 0($sp)
beq $a1, $zero, zero
move $v0, $a0
sub $a1,$a1,1
bge $a1,1,prod
move $v1,$a0
jal sum
move $a0, $v0
move $a1,$v1
jal prod
lw $ra, 0($sp)
move $v0,$a0
addi $sp, $sp, 12 #ripristino dello stack
jr $ra

sum:

lw $ra, 0($sp)
move $a0,$v0
move $a1,$v1
beq $a1, $zero, x
addi $v0,$a0,1
sub $v1,$a1,1
jr $ra

x:
lw $ra, 0($sp) #prima di tutto recupero l'indirizzo di ritorno e lo carico in $ra
addi $sp, $sp, 16 #ripristino lo stack sommando il numero di byte che gli avevo sottratto all'inizio della procedura
move $v0, $a0 #ritorno il valore di x
jr $ra #torno al chiamante


zero: #oltre a ritornare il valore zero devo anche ripristinare lo stack

lw $ra, 0($sp) #prima di tutto recupero l'indirizzo di ritorno e lo carico in $ra
addi $sp, $sp, 16 #ripristino lo stack sommando il numero di byte che gli avevo sottratto all'inizio della procedura
li $v0, 0 #ritorno il valore zero
jr $ra #torno al chiamante

############################## procedura main

main:
li $v0, 4
la $a0, inserisci1
syscall

#si legge l'intero scelto dall'utente
li $v0, 5
syscall

move $t1, $v0 #l'intero scelto si passa come parametro alla procedura

li $v0, 4
la $a0, inserisci2
syscall

#si legge l'intero scelto dall'utente
li $v0, 5
syscall

move $a1, $v0 #l'intero scelto si passa come parametro alla procedura
move $a0,$t1
jal prod

move $t0, $v0 #si copia il valore in $t0 perchè $v0 deve essere usato per la syscall

li $v0, 4
la $a0, risultato
syscall

#si stampa il valore copiandolo da $t0 in $a0
li $v0, 1
move $a0, $t0
syscall

#uscita dal programma
li $v0, 10
syscall

non mi torna ! se metto x= 3 e y = 2 mi da 4 !! perchè ?
mi potete aiutare ?

18 Risposte

  • Re: Procedure annidate

    Il motivo e semplice
    c'è un errore nel blocco
    move $v0, $a0
    sub $a1,$a1,1
    bge $a1,1,prod
    move $v1,$a0
    jal sum
    la bge e sbagliata infatti viene eseguita sempre la sum.
    prova a fare
    
    move $v0, $a0
    move $v1,$a1
    sub $a1,$a1,1
    bge $a1,1,prod
    move $v1,$a0
    jal sum
    fammi sapere se cosi va bene
    spero di esserti stato di aiuto
  • Re: Procedure annidate

    No, da sempre 4 !! è un dilemma..
  • Re: Procedure annidate

    Ho provato anche così ma non funziona..

    prod:
    sub $sp, $sp,12 #si crea l'area di memoria per la procedura
    sw $a0, 4($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $a1, 8($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $ra, 0($sp) #essendo ricorsiva, salvo il registro di ritorno $ra nella pila
    beq $a1, $zero, zero #se l'intero è zero devo ritornare questo valore
    sub $a1,$a1,1
    sw $a1, 8($sp)
    jal sum
    move $a0,$v0
    move $a1,$v1
    jal prod
    lw $ra, 0($sp)
    move $v0,$a0
    addi $sp, $sp, 12 #ripristino dello stack
    jr $ra

    sum:
    lw $ra, 0($sp)
    lw $a1, 8($sp)
    lw $a0, 4($sp)
    beq $a1,$zero, x
    sub $a1,$a1,1
    sw $a1, 8($sp)
    addi $a0,$a0,1
    sw $a0, 4($sp)
    jal sum
    move $v0,$a0
    move $v1,$a1
    jr $ra
  • Re: Procedure annidate

    Iniziamo dal main
    #si legge l'intero scelto dall'utente
    primo:
    li $v0, 5
    syscall
    blez $v0, $zero, primo # cosi se per sbaglio inserisco 0 o un numero inferiore me lo fa reinserire
    move $t1, $v0 #l'intero scelto si passa come parametro alla procedura
    li $v0, 4
    la $a0, inserisci2
    syscall
    #si legge l'intero scelto dall'utente
    secondo:
    li $v0, 5
    syscall
    bltz $v0,$zero,secondo # cosi se per sbaglio il numero e negativo me lo fa reinserire.
    move $a1, $v0 #l'intero scelto si passa come parametro alla procedura
    #nella proc 
    beq $a1,$zero,x
    sub $a1,$a1,1 #decremento y di 1
    add $t1,$t1,$a1 #sommo x e y
    add $t1,$t1,1 # aggiungo 1 formula totale 1+somma(x,y-1)
    # poi vado a stampare il risultato
    questa è la sequenza logica che dovresti usare.
    adesso stà a te collocare nel posto giusto il codice che ti ho scritto e scrivere il programma. pultroppo non ho QtSpim cosi non ho potuto provare il codice che ti ho scritto ma penso che dovrebbe funzionare.

    i link sottostanti possono tornarti molto utili
    http://twiki.di.uniroma1.it/pub/Users/FranzSerraCassano/Assembler.pdf

    http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html
  • Re: Procedure annidate

    Grazie mille! ora ci provo, poi ti faccio sapere.
  • Re: Procedure annidate

    Add $t1,$t1,$a1 #sommo x e y

    non dovrebbere essere
    add $t1,$a0,$a1

    ?
  • Re: Procedure annidate

    Secondo me la logica sarebbe:
    prod(3,2)-> sum(3,prod(3,1)) -> sum(3,sum(3,prod(3,0)))

    quindi il prod fa 0 -> sum(3,sum(3,0)) -> sum(3,3)

    che ne dici? ma non so come implementarla..
  • Re: Procedure annidate

    Allora
    l'istruzione add funziona nel seguente modo :
    add registro che deve ospitare i dati, registro 1 da sommare, registro 2 /costante da sommare:
    esempio :
    a = b+c = add $a0,$a1,$t1
    a = b+3 = add $a0,$a1,3
    il prodotto lo puoi calcolare nel seguente modo :
    ciclo:
    add $a0,$t1,$t1 # qui uso la forma x = altra variabile/registro + x
    sub $a1,$a1,1 #decremento y di 1
    bne $a1,$zero,ciclo # qui salto e vado a ripetere l'operazione se y non è uguale a zero.
    #qui poi procedo per visualizzare il risultato
    spero di esserti stato d'aiuto
    però vedi di leggere quei link che ti ho postato!
  • Re: Procedure annidate

    Scusa !!! ma non riesco a capire la logica del tuo segmento di codice!
    vorrei capire come posso implementare le due procedure perchè così non mi torna.. grazie del tuo aiuto !
  • Re: Procedure annidate

    Allora la logica del codice e la seguente
    accetto un numero (x) e lo metto in $t1 dopo aver controllato che non sia <= 0
    accetto un secondo numero (y) e lo metto in $a1 dopo aver controllato che non sia <= 0
    effettuo un ciclo del tipo for da y a 0 (quando y=0 il ciclo si ferma)
    prendo una variabile $a0 e gli sommo x
    poi decremento di uno y
    verifico che y non è = 0 e se y > 0 ripeto le operazioni fatte in precedenza.
    altrimenti stampo il risultato e termino il programma.
    esempio x=4 y=3 a=0
    a=0+4 = 4
    y=3-1 = 2
    condizione avverata no y > 0
    a=4 + 4 = 8
    y=2 - 1 = 1
    condizione avverata no y > 0
    a=8 + 4 = 12
    y=1 - 1 = 0
    condizione avverata si y = 0
    stampo il risultato e termino il programma.
    il prodotto sarà 12 infatti 4 * 3 = 12

    comunque scusami ma un errore lo avevo commesso l'add giusta non è add $a0,$t1,$t1
    perchè rappresenta a=x+x il che fatto una volta non sarebbe mai cambiato!
    l'istruzione giusta è add $a0,$a0,$t1
    perchè rappresenta a=a+x
    spero che questa volta sono riuscito a farmi capire
  • Re: Procedure annidate

    L'ho implementato ma non funziona il ciclo ! cmq sei stato chiarissimo GRAZIE !

    prod:
    sub $sp, $sp,12 #si crea l'area di memoria per la procedura
    sw $a0, 4($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $a1, 8($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $ra, 0($sp)
    move $t1,$zero
    beq $a1, $zero, zero
    beq $a1, 1 , x
    ciclo:
    jal sum
    bne $a1,0,ciclo
    lw $ra, 0($sp)
    addi $sp, $sp, 12 #ripristino dello stack
    jr $ra

    sum:
    lw $ra, 0($sp)
    sub $a1,$a1,1 #decremento y di 1
    add $t1,$a0,$t1 # somma di x
    move $v0,$t1
    jr $ra

    x:
    lw $ra, 0($sp) #prima di tutto recupero l'indirizzo di ritorno e lo carico in $ra
    addi $sp, $sp, 16 #ripristino lo stack sommando il numero di byte che gli avevo sottratto all'inizio della procedura
    move $v0, $a0 #ritorno il valore di x
    jr $ra #torno al chiamante


    zero: #oltre a ritornare il valore zero devo anche ripristinare lo stack

    lw $ra, 0($sp) #prima di tutto recupero l'indirizzo di ritorno e lo carico in $ra
    addi $sp, $sp, 16 #ripristino lo stack sommando il numero di byte che gli avevo sottratto all'inizio della procedura
    li $v0, 0 #ritorno il valore zero
    jr $ra #torno al chiamante
  • Re: Procedure annidate

    Invece così funziona ma non mi pare che rispetti le due funzioni
    prod(x,y) = { 0 se y=0 oppure somma(x,prod(x,y-1)) }
    somma(x,y)= { x se y=0 oppure [1+ somma(x,y-1)] }

    secondo te le rispetta ?

    prod:
    sub $sp, $sp,12 #si crea l'area di memoria per la procedura
    sw $a0, 4($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $a1, 8($sp) #essendo ricorsiva, memorizza l'intero passato come argomento
    sw $ra, 0($sp)
    move $t1,$zero
    beq $a1, $zero, zero
    beq $a1, 1 , x
    jal sum
    lw $ra, 0($sp)
    addi $sp, $sp, 12 #ripristino dello stack
    jr $ra

    sum:
    lw $ra, 0($sp)
    sub $a1,$a1,1 #decremento y di 1
    add $t1,$a0,$t1 # somma di x
    bne $a1,0,sum
    move $v0,$t1
    jr $ra
  • Re: Procedure annidate

    questo tipo di esercizi ha l'unico scopo di far imparare come si costruisce un ciclo del tipo for.
    tra poco farai esercizi anche su come si costruicono cicli del tipo do while

    la prima parte quella del prodotto si (affronto sempre un problema alla volta!)
    prod(x,y) = { 0 se y=0 oppure somma(x,prod(x,y-1)) }
    dalla definizione abbiamo escluso solamente il caso in cui y=0 all'inizio
    beq $a1, $zero, zero #basta che crei la label zero dove andrai a mettere la stampa "prod(x,y)=0"
    la seconda parte dell'esercizio quella della somma.
    somma(x,y)= { x se y=0 oppure [1+ somma(x,y-1)] }
    si intente in questa maniera somma 1 a x fin quando y > 0 e se y inizialmente è 0 restituisci x
    in quanto ogni numero sommato a 0 da sempre il numero.
    esempio 2+0=2
    esempio esercizio seconda parte
    inizialmente x=3 y=2
    x=x+1
    solito ciclo fin quando y<>0
    x=3+1 = 4
    y=2-1 = 1
    y=0 ? no
    x=4+1 = 5
    y=1-1 = 0
    y= 0 ? si stampa il risultato e termina il programma.
    modificando un pò il programma puoi fare entrambe le operazioni all'interno dello stesso ciclo.
    per far ciò basta che inserici un altra variabile esempio $a2 = x (questa assegnazione la metti fuori del ciclo)
    nel ciclo basta che inserisci add $a2,$a2,1
    ricordati che alla label zero dovrai inserire sia la stampa del prodotto che la stampa della somma che varranno 0 per il prodotto e x per la somma.
    una curiosità a cosa ti serve l'istruzione?
    beq $a1, 1 , x
    per farti fare un pò di pratica ti propongo un esercizio facile facile
    esercizio :
    dato un numero intero positivo > 1 calcola e stampa a video la sua tabellina.
    spero di esserti stato d' aiuto
  • Re: Procedure annidate

    Se y =1 allora stampo X
    Cmq le due procedure sono legate nello stesso esercizio !
    Cioè calcolare il proddotto( x per y ) con quelle due funzioni !
Devi accedere o registrarti per scrivere nel forum
18 risposte