|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Messaggi: n/a
|
[Generico] chiarimento su funzione ricorsiva
Ciao a tutti,
avrei bisogno di un chiarimento, passo passo, per capire l'esatto funzionamento di una funzione ricorsiva. Premesso che l'algoritmo e l'utilità mi è chiara, non riesco a focalizzare come venga costruito il risultato finale di tale funzione. Mi spiego: prendiamo la classica serie di Fibonacci, risolta qui sotto con una funzione ricorsiva in Ruby. Codice:
def fattoriale(x)
risultato = 0
if (x == 0)
risultato = 1
else
risultato = x * fattoriale(x - 1)
end
risultato
end
puts fattoriale(4)
Codice:
risultato = x * fattoriale(x - 1) Grazie in anticipo. |
|
|
|
#2 |
|
Messaggi: n/a
|
Forse così: 4 x ( 3 x ( 2 x ( 1 x 1) ) ) ?
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: May 2001
Messaggi: 12939
|
Il trucco è seguire passo passo le chiamate della funzione (prova ad eseguire la funzione "a mano" con carta e penna).
Supponendo che tu conosca bene il meccanismo delle chiamate a funzione (in generale), quello che devi notare è che ad ogni passo (se x > 0) viene chiamata la funzione con il parametro x decrementato di 1. Questo significa che ad un certo punto dell'esecuzione arrivi al passo base, ovvero x = 0 (di fatto lì si interrompe la catena ricorsiva, perché la funzione ritorna 1). |
|
|
|
|
|
#4 | |
|
Messaggi: n/a
|
Quote:
Si si questo l'avevo capito. Ho provato a mettere un puts davanti a Codice:
risultato = x * fattoriale(x - 1) mi ritrovo in output: Codice:
1 2 6 24 Ad ogni chiamata infatti viene re-inizializzato a 0
|
|
|
|
|
#5 |
|
Messaggi: n/a
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Mar 2007
Messaggi: 7863
|
|
|
|
|
|
|
#7 | |
|
Messaggi: n/a
|
Conosco stack, queue ecc. ma solo superficialmente. Non ho fatto l'UNI.
Ho trovato questo: Quote:
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
lo stack è una parte della memoria riservata alla memoria statica e alle chiamate a funzione, ogni volta che una funzione viene chiamata, viene allocata la memoria di cui necessita nello stack, e quando la chiamata finisce viene liberata (si chiama stack proprio perché funziona con politica lifo)
ad esempio, ogni volta che chiami la funzione fattoriale, viene allocata una nuova variabile risultato (quindi l'indirizzo su cui viene scritto il risultato per n sarà diverso dall'indirizzo su cui lo scrive per n-1) tutto quello che devi pensare quando scrivi una funzione ricorsiva è: posso risolvere un problema servendomi della soluzione a un problema "più piccolo" dello stesso tipo, in modo da potermi fermare prima o poi perché conosco la soluzione di un caso base? il funzionamento delle stack, l'albero delle chiamate ti possono aiutare a renderti conto che la cosa funziona |
|
|
|
|
|
#9 | |
|
Messaggi: n/a
|
Quote:
Mi potete confermare (o smentire) che, di fatto, il calcolo del risultato finale avviene partendo dalla chiamata più interna della ricorsione per, via via, tornare alla prima chiamata? Cioè che in sostanza il calcolo avviene in una forma simile: Codice:
(1x2x3x4) Codice:
(4x3x2x1) Codice:
fattoriale(4) Ultima modifica di anonimizzato : 01-08-2010 alle 13:34. |
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Apr 2010
Città: Frosinone
Messaggi: 416
|
se vuoi sapere se è così nella funzione che hai scritto, la risposta è sì
non puoi "linearizzare" così però diciamo che è più come dire 4! = 4 * 3! e poi prendere un pezzo di carta su cui calcolare 3! = 3 * 2!, finché non arrivi a 0! fattoriale che sai essere 1 Ultima modifica di tuccio` : 01-08-2010 alle 13:42. |
|
|
|
|
|
#11 |
|
Messaggi: n/a
|
|
|
|
|
#12 | |
|
Messaggi: n/a
|
Quote:
Anche scritta in questo modo infatti si intuisce la ricorsione. Codice:
4 * 3! 3! = 3 x 2! 2! = 2 x 1! |
|
|
|
|
#13 |
|
Senior Member
Iscritto dal: Mar 2007
Messaggi: 7863
|
Devi avere ben chiaro in mente come vengono allocati i record di attivazione delle varie chiamate a funzioni e le successive deallocazioni. Ha poco senso semplificare, come ti è stato detto, la cosa ad una visione lineare.
Ultima modifica di nuovoUtente86 : 01-08-2010 alle 14:01. |
|
|
|
|
|
#14 | |
|
Messaggi: n/a
|
Quote:
Nel caso hai qualche riferimento online dove mi possa studiare meglio la cosa? Grazie ancora. |
|
|
|
|
#15 | |
|
Senior Member
Iscritto dal: Mar 2007
Messaggi: 7863
|
Quote:
|
|
|
|
|
|
|
#16 | |
|
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
|
|
|
|
|
#17 |
|
Messaggi: n/a
|
|
|
|
|
#18 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
Gli basta sapere ad ogni istante i valori delle variabili locali e dei parametri attuali. Sgurbat: ribadisco, come ti era già stato consigliato, di seguire passo su passo su carta l'intera esecuzione con valori semplici Prendendo l'esempio sopra, per scriverlo su carta scrivi il nome della funzione con i parametri attuali, seguita dalle operazioni eseguite e per ogni ricorsione indenta. Codice:
fattoriale(4):
risultato = 4 * fattoriale(3)
fattoriale(3):
risultato = 3 * fattoriale(2)
fattoriale(2):
risultato = 2 * fattoriale(1)
fattoriale(1):
risultato = 1 * fattoriale(0)
fattoriale(0):
risultato = 1
risultato = 1
risultato = 2
risultato = 6
risultato = 24
Ad esempio: Passo 0: - fattoriale(0) = 1 Passo 1: - fattoriale(1) = 1 * fattoriale(0) Passo n: - fattoriale(n) = n * fattoriale(n-1) In questo caso c'è un solo passo 0, che corrisponde ad una condizione di arresto. Nel caso ci fossero diverse condizioni di arresto, dovrai esplorare un passo 0 ed un passo 1 per ogni condizione di arresto. Il passo 1 corrisponde ad una chiamata della funzione che genera una ulteriore singola chiamata ricorsiva, la quale mette in atto la condizione di arresto da testare. Questo modo di pensare ti tornerà molto utile anche per scrivere le funzioni ricorsive, non solo per capirle. Ultima modifica di cionci : 01-08-2010 alle 19:15. |
|
|
|
|
|
|
#19 | |
|
Senior Member
Iscritto dal: Mar 2007
Messaggi: 7863
|
Quote:
|
|
|
|
|
|
|
#20 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Secondo me ha poco senso conoscere il record di attivazione per comprendere come funzionano le chiamate ricorsive, anche perché il formato del record di attivazione non è standard e dipende dal compilatore e dalla macchina fisica/virtuale per cui si va a compilare/interpretare il linguaggio.
Giusto per fare un esempio comune: il formato del record di attivazione varia ad esempio fra IA32 e x86-64... Ad esempio in x86-64 non esiste un vero e proprio record di attivazione, ma per chiamate fino a, mi sembra, 8 parametri si fa uso dei registri general purpose per passare i parametri. Quindi anche semplicemente parlare di record di attivazione e stack in questo caso perde di significato. Poi se si va a parlare di linguaggi interpretati/compilati JIT come nel caso sopra (è Ruby se non erro) le cose si fanno ancora più complicate... Ultima modifica di cionci : 02-08-2010 alle 13:09. |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 03:15.




















