Fibonacci som rekursiv

Tags:    rekursion java programmering fibonacci matematik

<< < 12 > >>
Hej allesammen

Jeg har fået stillet en opgave, eller nærmere to opgaver, men den første har jeg løst. Opgaverne lyder:
1. Lav en metode der benytter en løkke til at finde fibonacci nummeret ud fra en given't term/nummer. Metoden skal returnere værdien som en long.
2. Lav nu den samme metode, men denne gang skal du benytte rekursion til at løse opgaven.

Jeg har løst opgave 1 på følgende måde:
Fold kodeboks ind/udJava kode 

Mit problem er nu at jeg ingen ide har til hvad jeg skal gøre for at lave metoden rekursiv. Ved godt at rekursion er noget med at metoden kalder sig selv, men kan bare ikke lige greje hvordan jeg løser den.

Håber at der er nogle der kan hjælpe mig :)



20 svar postet i denne tråd vises herunder
15 indlæg har modtaget i alt 23 karma
Sorter efter stemmer Sorter efter dato
Hej Jesper

Jeg har engang løst en lignende opgave, og du skal kalde din metode 2 gange rekursivt, bare med et andet term/nummer. Min løsning hurtigt kunne se således ud
Fold kodeboks ind/udJava kode 

Som du kan se returnerer jeg resultatet af 2 rekursive kald, bare hvor den første har et nummer mindre end før, og den anden to numre mindre. på den måde opnår du effekten af at det foregående resultat adderes med det næste fibonacci tal i rækken.

håber at du kunne bruge dette til noget, og hvis du er i tvivl er du velkommen til at spørge.



Indlæg senest redigeret d. 29.10.2011 09:47 af Bruger #4487
Fold kodeboks ind/udJava kode 


Det smarte ved rekursive funktioner er, at opgaver typisk bliver meget nemmere at løse. Ulempen er dog, at med mindre man bruger tail recursion, så ender metodekald med at blive utroligt langsomme, idet de forgræner sig så meget. Overvej fx her, at der vil være omkring 2^n kald til fibonacci-metoden blot for at beregne de n første fibonacci-tal.

Martin: Så benyt iteration, når performance er super vigtig, og benyt rekursion når performance ikke er så vigtig, men måske mere læsbarheden. Det er hvertfald hvad jeg har fået fortalt.

Jeg vil ikke engang sige, at han skal benytte det, når det er super vigtigt, men bare når performance har den mindste indflydelse. Udførselshastigheden bliver eksponentielt større, dvs. en udregning, der måske ville tage 2 sekunder kan ende med at tage flere minutter. Det er ikke bare et lille performanceudsving, rekursion kan skabe.



Indlæg senest redigeret d. 29.10.2011 16:18 af Bruger #16825
Det helt store problem med rekursiv udregning af fibonacci tal er ikke at der skal gemmes resultater, men snarere at mange beregninger skal udregnes mange gange. Jeg har lavet et træ til at vise, hvad der skal til, for at beregne det 10. fibonacci tal rekursivt: http://www.the-playground.dk/uploads/images/software/fib.png

fib(10) kalder videre til fib(9) og fib(8). fib(9) kalder så også videre til fib(8) og fib(7), og så videre.
Som det kan ses, så bliver de samme beregninger og subtræer, beregnet mange gange, og det bliver værre for høje fibonacci tal.

Jeg brugte følgende kode til at generere tegningen:
Fold kodeboks ind/udC kode 


Resultatet fodrede jeg til Graphiviz Dot værktøjet, som kan hentes herfra: http://www.graphviz.org/



Indlæg senest redigeret d. 30.10.2011 00:05 af Bruger #2695
En anden ting som er en væsentlig forskel på rekursion og den iterative løsning, udover mulige forskelle i performance, er at for hvert rekursiv kald så vil stakken (indeholder lokal variabler for alle funktioner/metoder som er under udførsel) vokse. I ekstreme tilfælde kan det betyde at stakken kan blive for stor og dette vil i de fleste programmeringssprog skabe noget lignende en StackOverflowException. Dette er typisk de samme tilfælde dog hvor den rekursive metode i forvejen ville have været alt for langsom langt før dette problem ville have opstået dog.

Det skal måske nævnes i samme ombæring at på trods af i f.eks. fibonacci tilfældet så har rekursion en "straf" - stakken vokser som sagt for hvert metode kald og dette koster en smule i performance. Typisk vil dette ikke være nok til at man bør tænke for meget på det, men er man i ekstreme miljøer er det værd at tænke over. Det skal selvfølgelig noteres her at der antages at der ikke er tale om tail recursion eller at det sprog man bruger ikke har en compiler som optimerer for dette (kort sagt - der findes en form for rekursion som kan, når man kompillerer sin kode, omskrives til en iterativ version - i visse sprog sker dette, f.eks. Haskell, Lisp og diverse andre funktionelle sprog)




Rekursion og løkker er to forskellige måder at arbejde på, så nej, det vil ikke (nødvendigvis) være relevant at begge tæller op.


Var måske en dårlig måde at forklare hvad jeg mente. Det jeg ville frem til var, at hvis i ønsker at sammenligne de to teknikker burde i sammenligne den bedste løsning i hver teknik.

Ikke at jeg forventer at rekursion derfor bliver bedre end løkken i dette tilfælde, men den bliver væsentlig mindre dårligere.



Indlæg senest redigeret d. 31.10.2011 09:53 af Bruger #5620
Man kan sige at rekursive metoder på mange måder er lettere at læse og hurtigere at implementere end iterative metoder (metoder der benytter løkker). Der er dog en stor ulempe med rekursion, nemlig den at hver gang vi udfører et rekursivt kald er vi nødt til at gemme resultatet, samt andre lokale variabler på stakken, hvilket betyder at hvis vi skulle finde fibonacci med et stort tal, så vil det tage lang tid for computeren at udføre i forhold til en iterativ metode. Du behøver nemlig ikke gemme mange resultater osv. i nye variabler, hvis metoden er iterativ.

Så benyt iteration, når performance er super vigtig, og benyt rekursion når performance ikke er så vigtig, men måske mere læsbarheden. Det er hvertfald hvad jeg har fået fortalt :P



Så benyt iteration, når performance er super vigtig, og benyt rekursion når performance ikke er så vigtig, men måske mere læsbarheden. Det er hvertfald hvad jeg har fået fortalt :P


Det er også rigtigt efter mine erfaringer.
Nu udvikler jeg godt nok i .NET men da jeg har haft lavet et større distribueret "bruteforce grid" med flere computere, hvor performance VAR super vigtig, der kunne jeg se et væsentligt performance hit ved rekursion i forhold til iteration. Og det var præcist den samme metode jeg havde implementeret.

Nu ved jeg godt at .NET heller ikke lige frem er berømt for sin rekursion, men just my five cents :)



Rekursion er godt til mange ting, men lige nøjagtig fibonacci er det er virkelig skidt løsning, da den beregner de samme dele mange gange.
Når du er færdig, så prøv at beregne det 30. fibonacci tal med henholdsvis rekursion og en løkke. Stor forskel.



Performance ved en løkke kan være ligeså god som ved rekursion, det kommer helt an på opgaven.
Skal du f.eks. beregne hvor mange data, der ligger i et bibliotek og underbiblioteker, så kan man bruge en løkke, men det vil være meget mere læsbart at bruge rekursion, og performancemæssigt vil det være det samme (eller forskellen vil være ubetydelig).
Pattern matching og parsing er noget nær umulig at gøre korrekt uden rekursion.

Fibonacci er bare det klokkeklare eksempel på at rekursion ikke altid er det korrekte at bruge.



Jeg vil gerne bede om en præcis forklaring på hvorfor min metode ikke er rekursiv.. :)



<< < 12 > >>
t