0

So, I have this task:
Where n is a positive integer, the function f(n) satisfies the following

f(0) = 0 
f(1) = 1
f(n) = f(n-1) + f(n-2) when n > 1
  1. Please create a program to find f(n)
  2. Use the program to find f(8181)

    const f = (n) => {
      if(n === 0) {
        return 0
      } else if(n === 1) {
        return 1
      } else if(n > 1) {
        return f(n-1) + f(n-2)
      } else {
        return null
      }
    }
    

above is the code that i have wrote but it only do just fine when i do n < 40, it starts to slow down when n > 41. it takes forever to load f(100) let alone f(8181)
so, is there any way to optimized this code to meet all the requirements?
thank you in advance!

ps: it's not a school task so i dont have anyone to consult

31piy
  • 23,323
  • 6
  • 47
  • 67
ergxpr0xy
  • 7
  • 5
  • For `n>2`, `f(n-1)` will involve calling `f(n-2)`, so you're doing twice as much work as needed for each iteration step. What should be an `O(n)` operation is becoming `O(2^n)`!! – Niet the Dark Absol Aug 21 '18 at 10:24
  • i know right, but the requirement said i should do the recursion. so im wondering if i could write a condition or something – ergxpr0xy Aug 21 '18 at 10:28
  • `const f = (src=>(n) => {while(src.length <= n) src[src.length] = src[src.length-1] + src[src.length-2]; return src[n];})([0,1]);` uses dynamic programming, not recursion - however, it is important to note that `f(79) > Number.MAX_SAFE_INTEGER` - for `n>=79` you will get approximate values. `f(8181)` returns `Infinity`. – Niet the Dark Absol Aug 21 '18 at 10:28
  • [`f(8181)` is a 1,710-digit number](http://www.maths.surrey.ac.uk/hosted-sites/R.Knott/Fibonacci/fibCalcX.html) - who assigned this insane task to you? – Niet the Dark Absol Aug 21 '18 at 10:32
  • Possible duplicate of [Fast Fibonacci recursion](https://stackoverflow.com/questions/13826810/fast-fibonacci-recursion) – t.niese Aug 21 '18 at 10:38
  • @NiettheDarkAbsol Sounds like a job interview question, or in general a question which has the claim that one thinks more about the problem than to implement it only stupidly. Finding a fast algorithm to calculate this recursion is not such a big deal. – t.niese Aug 21 '18 at 10:46

2 Answers2

1

You can use memoization to optimize the algorithm.

The idea is to remember the result of f(n - 1) + f(n - 2) in a JS object so that further calculations can use the memoized result instead of re-calculating everything.

Following is a demo, which instantly prints the result for f(100) correctly.

let dict = {};

const f = (n) => {
  if (n === 0) {
    return 0
  } else if (n === 1) {
    return 1
  } else if (n > 1) {
    if (!dict[n]) {
      dict[n] = f(n - 1) + f(n - 2);
    }

    return dict[n];
  } else {
    return null
  }
}

console.log(f(100));
31piy
  • 23,323
  • 6
  • 47
  • 67
  • ah thank you!! it works. i even just heard that there is something like memoization principal lol – ergxpr0xy Aug 21 '18 at 10:37
  • `f(100)` is `354 224 848 179 261 915 075`, which is rather different from the `354 224 848 179 262 000 000` your code gives ;) – Niet the Dark Absol Aug 21 '18 at 10:38
  • @NiettheDarkAbsol -- Did you really compare the values? :D I suppose this behaviour is due to limitations of JavaScript numbers. But the crux is memoization here. :) – 31piy Aug 21 '18 at 10:39
  • I used the calculator I found and linked in a comment on the question :D And yeah. Floats are accurate to about 14-15 significant digits, which is only enough up to `f(78)`. – Niet the Dark Absol Aug 21 '18 at 10:40
  • @ergxpr0xy -- please consider accepting this answer if it solved your problem. – 31piy Aug 22 '18 at 04:06
  • @NiettheDarkAbsol ah sure sorry! – ergxpr0xy Aug 22 '18 at 11:09
0

@31piy - Avoid using recursion as it is not memory efficient also because each function is getting pushed in call-stack which slows down program. Here is the program for Fibonacci series till n number without recursion.

Hope this will help you :)

/**
 * Method to return Fibonacci series with linear (without recursion)
 * @param {*} n 
 */
function getFibonacciSeries(n){
    var n1 = 0, n2 = 1, a = [], n3;
    a.push(n1);
    a.push(n2);
    for(i=2; i < n; i++){
        n3 = n1 + n2;
        a.push(n3);
        n1 = n2;
        n2 = n3;
    }
    console.log(a);
    return a[n-1];
}
A. Todkar
  • 353
  • 2
  • 10
  • This is nice, but it re-builds the entire array each time you call the function. Far better to have a single static array that persists across function calls. Just extend the array if the new call is higher than any previous call. – Niet the Dark Absol Aug 21 '18 at 10:41
  • @NiettheDarkAbsol - You are right, that is more optimized one. – A. Todkar Aug 21 '18 at 10:43
  • FYI -- The solution I proposed doesn't recurse much. If it finds the value in the `dict` object, then no recursion takes place. So, I think, the entire call-stack limits to 2-3 frames (didn't evaluate yet though). – 31piy Aug 21 '18 at 10:47