Java Program Fibonacci Sequence

↘锁芯ラ 提交于 2019-12-29 06:25:20

问题


I am writing a "simple" program to determine the Nth number in the Fibonacci sequence. Ex: the 7th number in the sequence is: 13. I have finished writing the program, it works, but beginning at the 40th number it begins to delay, and takes longer, and longer. My program has to go to the 100th spot in the series.

How can I fix this so it doesn't take so long? This is very basic program, so I don't know all the fancy syntax codes.. my formula is:

if n =1 || n = 0
   return n;

else 
    return F(n-1) + F(n-2);

This works great until it goes past the 40th term. What other statement do I have to add to make it go quicker for higher numbers??


回答1:


The problem is that because you are using simple recursion, you re-evaluate F(n) multiple times, so your execution time is exponential.

There are two simple ways to fix this:

1) Cache values of F(n) when they are evaluated the first time. Check the cache first before evaluating F(n) to see if you have already calculated it for this n.

2) Use an iterative approach: Calculate F(1), F(2), F(3), etc... until you reach the number you need.




回答2:


The issue is that your algorithm, while mathematically pure (and nice) isn't very good.
For every number it wants to calculate, it has to calculate two lower ones which in turn have to calculate two lower ones, etc. Your current algorithm has a Big O notation complexity of about O(1.6n), so for very large numbers (100 for example) it takes a long time.

This book, Structure and Interpretation of Computer programs has a nice diagram: showing what happens when you generate fib 5 with your algorithm

(source: mit.edu)

The simplest thing to do is to store F - 1 and F - 2, so that you don't have to calculate them from scratch every time. In other words, rather than using recursion, use a loop. Than means that the complexity of the algorithm goes from O(1.6n) to O(n).




回答3:


There are a number of solutions. The most straightforward is to use memoization. There's also Binet's formula which will give you the nth fibonacci number in constant time.

For memoization, you store your results for F[a_i] in a map or list of some kind. In the naive recursion, you compute F[4] hundreds of thousands of times, for example. By storing all these results as you find them, the recursion ceases to proceed like a tree and looks like the straightforward iterative solution.

If this isn't homework, use Binet's formula. It's the fastest method available.




回答4:


Try this example, it calculates the millionth Fibonacci number in a reasonable time frame without any loss of precision.

import java.math.BigInteger;

/*
250000th fib # is: 36356117010939561826426 .... 10243516470957309231046875
Time to compute: 3.5 seconds.
1000000th fib # is: 1953282128707757731632 .... 93411568996526838242546875
Time to compute: 58.1 seconds.
*/
public class Fib {
    public static void main(String... args) {
        int place = args.length > 0 ? Integer.parseInt(args[0]) : 1000 * 1000;
        long start = System.nanoTime();
        BigInteger fibNumber = fib(place);
        long time = System.nanoTime() - start;

        System.out.println(place + "th fib # is: " + fibNumber);
        System.out.printf("Time to compute: %5.1f seconds.%n", time / 1.0e9);
    }

    private static BigInteger fib(int place) {
        BigInteger a = new BigInteger("0");
        BigInteger b = new BigInteger("1");
        while (place-- > 1) {
            BigInteger t = b;
            b = a.add(b);
            a = t;
        }
        return b;
    }
}



回答5:


Create an array with 100 values, then when you calculate a value for Fib(n), store it in the array and use that array to get the values of Fib(n-1) and Fib(n-2).

If you're calling Fib(100) without storing any of the previously calculated values, you're going to make your java runtime explode.

Pseudocode:

array[0] = 0;
array[1] = 1;
for 2:100
array[n] = array[n-1] + array[n-2];



回答6:


The problem is not JAVA, but the way you are implementing your Fibonacci algorithm. You are computing the same values many times, which is slowing your program.

Try something like this : Fibonacci with memoization




回答7:


                           F(n)
                            /    \
                        F(n-1)   F(n-2)
                        /   \     /      \
                    F(n-2) F(n-3) F(n-3)  F(n-4)
                   /    \
                 F(n-3) F(n-4)

Notice that many computations are repeated! Important point to note is this algorithm is exponential because it does not store the result of previous calculated numbers. eg F(n-3) is called 3 times.

Better solution is iterative code written below

function fib2(n) {
    if n = 0 
       return 0
    create an array f[0.... n]
    f[0] = 0, f[1] = 1
    for i = 2...n:
       f[i] = f[i - 1] + f[i - 2]
    return f[n]    
}

For more details refer algorithm by dasgupta chapter 0.2




回答8:


My solution using Java 8 Stream:

public class Main {
    public static void main(String[] args) {
        int n = 10;
        Fibonacci fibonacci = new Fibonacci();
        LongStream.generate(fibonacci::next)
                .skip(n)
                .findFirst()
                .ifPresent(System.out::println);
    }
}

public class Fibonacci {
    private long next = 1;
    private long current = 1;

    public long next() {
        long result = current;
        long previous = current;
        current = next;
        next = current + previous;
        return result;
    }
}



回答9:


If you use the naive approach, you'll end up with an exploding number of same calculations, i.e. to calc fib(n) you have to calc fib(n-1) and fib(n-2). Then to calc fib(n-1) you have to calc fib(n-2) and fib(n-3), etc. A better approach is to do the inverse. You calc starting with fib(0), fib(1), fib(2) and store the values in a table. Then to calc the subsequent values you use the values stored in a table (array). This is also caled memoization. Try this and you should be able to calc large fib numbers.




回答10:


This is the code in Python, which can easily be converted to C/Java. First one is recursive and second is the iterative solution.

def fibo(n, i=1, s=1, s_1=0):
    if n <= i: return s
    else: return fibo(n, i+1, s+s_1, s)


def fibo_iter_code(n):
    s, s_1 = 1, 0
    for i in range(n-1):
       temp = s
       s, s_1 = s+s_1, temp
       print(s)



回答11:


Too slow...

Better: (JavaScript example)

function fibonacci(n) {
    var a = 0, b = 1;

    for (var i = 0; i < n; i++) {
        a += b;
        b = a - b;
    }
    return a;
}



回答12:


import java.util.*;
public class FibonacciNumber
{

  public static void main(String[] args)
  {
    int high = 1, low = 1;
    int num;
    Scanner in = new Scanner(System.in);
    try
    {
      System.out.print("Enter Number : " );
      num = in.nextInt(); 
      System.out.println( low);
      while(high < num && num < 2000000000)
      {
        System.out.println(high);
        high = low + high;
        low = high - low;
      }
     } catch (InputMismatchException e) {
       System.out.print("Limit Exceeded");
     }
   }
}

/* Ouput : 
Enter Number : 1999999999
1
1
2
3
5
8
13
21
34
55
89
144
233
377
610
987
1597
2584
4181
6765
10946
17711
28657
46368
75025
121393
196418
317811
514229
832040
1346269
2178309
3524578
5702887
9227465
14930352
24157817
39088169
63245986
102334155
165580141
267914296
433494437
701408733
1134903170
1836311903
-1323752223
512559680
-811192543
-298632863
-1109825406
-1408458269
 1776683621
 368225352   */



回答13:


Naive implementation is natural and elegant but during execution recursive calls are creating binary tree. Beside already mentioned memoization, cashing of previous F(n) results and avoiding of unnecessary tree traversal, you can go for tail call optimization, already mentioned iterative or matrix multiplication. For example, Java 8 memoization:

private static final Map<Long, Long> memo = new HashMap<>();
static {
  memo.put(0L, 0L);
  memo.put(1L, 1L);
}
public static void main(String[] args) {
  System.out.println(fibonacci(0));
  System.out.println(fibonacci(43));
  System.out.println(fibonacci(92));
}
public static long fibonacci(long n) {
  return memo.computeIfAbsent(n, m -> fibonacci(m - 1) + fibonacci(m - 2));
}

Or maybe tail call optimized version:

interface FewArgs<T, U, V, R> {
  public R apply(T t, U u, V v);
}

static FewArgs<Long, Long, Long, Long> tailRecursive;

static {
  tailRecursive = (a, b, n) -> {
    if (n > 0)
      return tailRecursive.apply(b, a + b, n - 1);
    return a;
  };
}

You call it with a = 0, b = 1, n is required nth Fibonacci number but must be smaller than 93. More efficient ways to calculate Fibonacci numbers are matrix squaring, you will find example on my blog, and Binet formula




回答14:


You can use the caching technic. Since f(n)= f(n-1)+f(n-2) , you'll calculate f(n-2) one more time when you calculate f(n-1). So simply treat them as two incremental numbers like below:

public int fib(int ithNumber) {
    int prev = 0;
    int current = 1;
    int newValue;
    for (int i=1; i<ithNumber; i++) {
        newValue = current + prev;
        prev = current;
        current = newValue;
    }
    return current;
}



回答15:


It looks better with multiple statements of ternary operator.

static int fib(int n) {
        return  n > 5 ? fib(n-2) + fib(n-1)
                      : n < 2 || n == 5 ? n
                                        : n - 1;
}


来源:https://stackoverflow.com/questions/1799990/java-program-fibonacci-sequence

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!