Two different way of recursion - java

I calculate fibonachi row in two different ways. Why fib1 executes much longer then fib2?
public class RecursionTest {
#Test
public void fib1() {
long t = System.currentTimeMillis();
long fib = fib1(47);
System.out.println(fib + " Completed fib1 in:" + (System.currentTimeMillis() - t));
t = System.currentTimeMillis();
fib = fib2(47);
System.out.println(fib + " Completed fib2 in:" + (System.currentTimeMillis() - t));
}
long fib1(int n) {
if (n == 0 || n == 1) {
return n;
} else {
return fib1(n - 1) + fib1(n - 2);
}
}
long fib2(int n) {
return n == 0 ? 0 : fib2x(n, 0, 1);
}
long fib2x(int n, long p0, long p1) {
return n == 1 ? p1 : fib2x(n - 1, p1, p0 + p1);
}
}
The output:
2971215073 Completed fib1 in:17414
2971215073 Completed fib2 in:0

Because both algorithms work entirely different. Let me show you this with fib(5).
if you call fib1(5), it internally calls fib1(4) und fib1(3), lets visualize that with a tree:
fib(5)
/ \
fib(4) fib(3)
now, fib(4) internally calls fib(3) and fib(2).
So now we have this:
fib(5)
/ \
fib(4) fib(3)
/ \ / \
fib(3) fib(2) fib(2) fib(1)
I think by now it is very obvious where this is going, you should be able to fill in the rest.
edit: Another thing you should notice here is, that it actually has to performe the same caclculation multiple times. In this picture, fib(2) und fib(3) are both called multiple times. And this gets worse if the starting number is bigger./edit
Now, let's take a look at fib2(5). It you call it with 0, it returns 0. Otherwise, it calls fib2x(n, 0,1)
So, we have a call to fib2x(5,0,1). fib2x(n, 0,1) now internally calls fib2x(n-1, p1, p0+p1) and so on.
So, lets see:
fib2x(5, 0,1) => fib2x(4, 1,1) => fib2x(3, 1, 2) => fib2x(2, 2, 3) => fib2x(1, 3, 5)
by then, it has reached the return condition and returns 5.
So, your algorithms work entirely different. The first one works recursively and from the top to the bottom.
The second one starts at 1 and works his way up. Actually, it is more iterative then recursive (it was probably written recursive to throw you off). It keeps the already calculated values instead of discarding them and therefore needs to invoke far less calculations.

The reason is two algorithms have different runtime complexities:
fib1 is in Ο(2n)
fib2 is in Ο(n)

Ultimately, it's because fib2 only uses tail end recursion. It only makes one recursive call at the end. Thus there isn't any "branching" associated with the recursion and leads to a linear time solution. The fact that it's a tail call also leads to certain compiler/VM optimizations where the recursion can be converted into an iterative procedure with lower overhead.
fib1 uses another recursive call in addition to the tail-call which causes the running time to be exponential.

fib1 is an algorithm with O(2^n) runtime. fib2 is an algorithm with O(n) runtime.
The reason for this is pretty cool -- it's a technique called memoization. The work the program does is saved at each step, avoiding any extraneous calculation.
You can see it happen by unrolling the loop a couple more steps:
long fib2(int n) {
return n == 0 ? 0 : fib2x(n, 0, 1);
}
long fib2x(int n, long p0, long p1) {
return n == 1 ? p1 : fib2xy(n - 1, 1, 1);
}
long fib2xy(int n, long p0, long p1) {
return n == 1 ? p1 : fib2xyz(n - 1, 1, 2);
}
long fib2xyz(int n, long p0, long p1) {
return n == 1 ? p1 : fib2xyz(n - 1, p1, p0 + p1);
}
You can unroll this loop to any arbitrary number in the fibonacci sequence; each step builds on the calculation stored previously in the stack until n is depleted. This is in contrast to the first algorithm, which must redo this work at every step. Nifty!

Related

How to ignore StackOverFlow error in Java? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I know why it gives the error, I don't want to correct it I want the system to ignore it and keep running.
I know that the recursion is not infinite and I need to know when it will stop although I am sure it will be in a very large number and after a good while of execution.
Thankssss.
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
I know that the recursion is not infinite
You "know" a falsehood.
public static int fun1(int begin, int end, int cont) {
if (begin >= end) {
return 1;
}
cont += fun1(begin, (begin + end) / 2, cont);
cont += fun1(begin + (end - begin) / 4, begin + 3 * (end - begin) / 4, cont);
cont += fun1((begin + end) / 2, end, cont);
return cont;
}
Consider what happens if we call fun1(0, 1, 0).
Is begin >= end? No; begin == 0 and end == 1. So we recurse.
What are the arguments for our recursive calls? (begin + end) / 2 is equal to (0 + 1) / 2 is equal to 1 / 2 is equal to 0, with integer division. So the first recursive call is fun1(0, 0, 0).
But the last recursive call is fun1(0, 1, 0). Wait. That looks familiar, yeah? (Never mind the middle one; we have already shown a fault.)
#Karl's answer explains why your function is actually infinitely recursive.
But you asked:
How to ignore StackOverFlow error in Java?
You cannot simply ignore it. If you do that, the program crashes (or a child thread dies, or something) and you don't get an answer.
You could do this:
Integer result = null;
try {
result = fun1(x, y, z);
} catch (StackOverflowError e) {
// We are ignoring this
}
if (result == null) {
System.out.println("cannot compute fun1(x,y,z)");
} else {
System.out.println("fun1(x,y,z) is " + result);
}
But when you look at this, we are not really ignoring the exception. We are catching it and (ultimately) dealing with it as a special case.
Note that you can get a StackOverflowError even in cases where the recursion is not infinite. For example, if I was to add two numbers using recursion:
public int add(int a, int b):
if (a < 0 || b < 0) {
throw new IllegalArgumentException("negative");
else if (a == 0) {
return b;
} else
return add(a - 1, b + 1);
}
Since Java (typically) doesn't do tail-call optimization, large enough arguments will give a StackOverflowError.
So what it the solution to StackOverflowErrors in cases where the function is not infinitely recursive?
One approach would be to use a larger thread stack size. This could be done by using the -Xss<value> option to set the default stacksize for the JVM. Alternatively, you can supply a stack size via the Thread constructor when creating a new thread. However, the maximum practical thread stack size is limited by the amount of available memory, and potentially by JVM, OS and hardware architectural limits.
A second approach is to translate the recursive function into an iterative form. But note that if you simply simulate the recursive calls using a stack implemented in software, you have to deal with the possibility that that data structure gets too big.
A third approach is to try and find an algebraic solution; i.e. turn this into a mathematical problem.
But note that there are some cases where none of the above will work. For example, consider the Ackermann function.

Evaluation order in Java

So I have this code for the Fibonacci sequence:
int fibonacci(int i, int[] memo) {
if (i == 0 || i == 1) return i;
if (memo[i] == 0) {
memo[i] = fibonacci(i - 1, memo) + fibonacci(i - 2, memo);
}
return(memo[i]);
}
My question is: fibonacci(i-1, memo) will always be evaluated before fibonacci(i-2, memo) correct?
Correct, from left to right.
First you will completely traverse the recursion with the left argument fibonacci(i - 1, memo) after that, when it moves the recursion tree up again, each time the right argument will get computed, again with a full recursive tree.
A quick search yield this image illustrating the process:
Note that many values are often computed multiple times. Your current approach tries to optimize this by caching results inside an array memo.

Determining the Big O of a recursive method with two recursive cases?

I am currently struggling with computing the Big O for a recursive exponent function that takes a shortcut whenever n%2 == 0. The code is as follows:
public static int fasterExponent(int x, int n){
if ( n == 0 ) return 1;
if ( n%2 == 0 ){
int temp = fasterExponent(x, n/2);
return temp * temp;
}
return x * fasterExponent(x, --n); //3
}
I understand that, without the (n%2 == 0) case, this recursive exponent function would be O(n). The inclusion of the (n%2 == 0) case speeds up the execution time, but I do not know how to determine neither its complexity nor the values of its witness c.
The answer is O(log n).
Reason: fasterExponent(x, n/2) this halfes the input in each step and when it reaches 0 we are done. This obviously needs log n steps.
But what about fasterExponent(x, --n);? We do this when the input is odd and in the next step it will be even and we fall back to the n/2 case. Let's consider the worst case that we have to do this every time we divide n by 2. Well then we do the second recursive step once for every time we do the first recursive step. So we need 2 * log n operations. That is still O(log n).
I hope my explanation helps.
It's intuitive to see that at each stage you are cutting the problem size by half. For instance, to find x4, you find x2(let's call this A), and return the result as A*A. Again x2 itself is found by dividing it into x and x.
Considering multiplication of two numbers as a primitive operation, you can see that the recurrence is:
T(N) = T(N/2) + O(1)
Solving this recurrence(using say the Master Theorem) yields:
T(N) = O(logN)

Learning Java - Do not fully understand how this sequence is calculated (Fibonacci) in for loop [duplicate]

This question already has answers here:
Java recursive Fibonacci sequence
(37 answers)
Closed 8 years ago.
I am learning Java and I have this code from the internet and running it in Eclipse:
public class Fibonacci {
public static void main (String [] args) {
for (int counter = 0; counter <= 3; counter++){
System.out.printf("Fibonacci of %d is: %d\n", counter, fibonacci(counter));
}
public static long fibonacci(long number) {
if ((number == 0) || (number == 1))
return number;
else
return fibonacci(number - 1) + fibonacci(number - 2);
}
}
I've tried to understand it but cannot get it. So I run through the code and counter gets passed in through the fibonacci method. As counter starts at 0 and this is what gets passed first, then 1 and I understand the method passes back 0 and then 1.
When it reaches 2: it will return 2-1 + 2-2 = 2 and it does return this.
When it reaches 3: it will return 3-1 + 3-2 = 3 but it does not return 3 it returns 2.
Please can someone explain to me why as I cannot figure this out?
Thanks
First, I have to tell you that this recursive version has a dramatic exponential cost. Once you understand how it works, my advice for you would be to learn about tail recursivity, write a tail-recursive solution, an iterative solution, and compare them to your current method for high values of "number".
Then, your function basically uses the mathematical definition of the Fibonacci sequence :
f0 = 1, f1 = 1, fn = fn-1 + fn-2 for all n >= 2
For example if we call fibonacci(3), this will return fibonacci(2) + fibonacci(1). fibonacci(2) will be executed first and will return fibonacci(1) + fibonnacci(0). Then fibonacci(1) will return immediately 1 since it is a terminal case. It happens the same thing with fibonnacci(0), so now we have computed fibonnacci(2) = 1 + 0 = 1. Let's go back to fibonacci(3) which has been partially evaluated at this point : 1 + fibonnacci(1). We just have to compute fibonnacci(1) and we can finally return 1 + 1 = 2.
Even in this little example, you can see that we evaluated twice fibonacci(1), that is why this version is so slow, it computes many times the same values of the sequence, and it gets worth when "number" is high.

How does this implementation of Fibonacci(n) work? [recursion]

Theres an exercise from a Java book I'm reading that has me confused:
A Fibonacci sequence is the sequence of numbers 1, 1, 2, 3, 5, 8,
13, 21, 34, etc., where each number (from the third on) is the sum
of the previous two. Create a method that takes an integer as an
argument and displays that many Fibonacci numbers starting from the
beginning. If, e.g., you run java Fibonacci 5 (where Fibonacci is
the name of the class) the output will be: 1, 1, 2, 3, 5.
I could have swore that it would need an array or some way of storing the previous numbers but when I saw the answer it wasn't the case:
import java.util.*;
public class Fibonacci {
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
public static void main(String[] args) {
// Get the max value from the command line:
int n = Integer.parseInt(args[0]);
if(n < 0) {
System.out.println("Cannot use negative numbers"); return;
}
for(int i = 1; i <= n; i++)
System.out.print(fib(i) + ", ");
}
}
Would someone be able to explain how using a function within itself produces this?
The code you gave is an example of a recursive solution. When the function is called for the first time, it executes until it calls itself. Its state is stored on the stack, and the code begins executing again with new input data. This process repeats until the input is less than 2, at which point 1 is returned, and the answer returns to the previous caller.
For example, calling fib(5) results in the following execution:
fib(5):
fib(4):
fib(3):
fib(2): 1
fib(1): 1
fib(2): 1
fib(3):
fib(2): 1
fib(1): 1
Note that you are partially correct. Intermediate results are stored on the stack in this solution. That is one of the reasons why the recursive solution is so expensive. The other is its O(2^n) complexity. However, if is possible to compute Fibonacci(n) iteratively and without storing all previous results. All you really need is to store the last to results and count from 1 up to n.
This is a recursive solution. A recursive function calls itself until a given stop condition is met. Then each call exits until only the first call remains. That first call outputs the result.
In your solution, the stop condition is :
if (n <= 2)
return 1;
until this condition is met, the function will make successive calls to itself. Each call reduces the int passed as a parameter. When it reaches 2, the stop condition dictates that the function returns with value 1 (the result of n=1 and n=2 in fibonacci(n) ).
Because the fibonacci is the sum of the last two numbers, the recursive part of the function,
return fib(n-1) + fib(n-2);
does a sum of n-1 and n-2 (as I said, the two last numbers of the sequence). When the n equals 2, these calls to function fib will finally have a value, and will be returned.
Example, if n = 3, the recursive part will call fib(2) and fib(1), both are equal or less than 2, so both calls will return 1. So the printf will print 1, 1, 2.
2 is the sum of 1 + 1 (I know it's obvious, but sometimes stating the obvious helps).
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)
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.
For more details refer algorithm by dasgupta chapter 0.2
This is the standard example for an recursive function.
The Fibonacci Numbers are declared recursive, too.
Both fib(1) and fib(2) are declared as 1. All others are calculated by adding the last two fibonacci numbers, so fib(3)=fib(2)+fib(1).
Compare this to the calculation method which does exactly this:
static int fib(int n) {
if (n <= 2)
return 1;
return fib(n-1) + fib(n-2);
}
By the way, this is a very slow way to calculate the fibonacci numbers, using two variables (you don't need all of them for the last one, only the last two!) and a loop is in O(n), the recursive function above has O(2^n) operations.

Categories