views:

212

answers:

8

I'm working on Project Euler problem #2:

Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:

1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

Find the sum of all the even-valued terms in the sequence which do not exceed four million.

My code:

public class Two {

public static void main(String[] args) {
    Two obj = new Two();
    int sum = 0, i = 1;

    while (obj.fibonacci(i) < 4000001) {

        if (obj.fibonacci(i) % 2 == 0) {
            sum += obj.fibonacci(i);
            i++;
        }

    }
    System.out.println(sum);

}

public int fibonacci(int n) {
    if (n == 0) {
        return -1;
    }
    if (n == 1) {
        return 1;
    }
    if (n == 2) {
        return 3;
    } else {
        return fibonacci(n-1)+fibonacci(n-2);

    }
}
}

Please help me that what is wrong with this code that when I run it. It doesn't show the output on the console and the total time will be over than 5 minutes

Thanks

+7  A: 

You're stuck in an infinite loop there as you're only increasing i when its mod 2 is equal to 0. You need to move your i++ lower.

 while (obj.fibonacci(i) <= 4000000) {

        if (obj.fibonacci(i) % 2 == 0) {
            sum += obj.fibonacci(i);
        }   
        i++;
    }

As other comments have metioned, this isn't the best way to solve the fibonacci problem, but it solves your error/problem. You should walk this through a debugger if you don't see why and you'll notice you use a lot of recursive calls which have already been solved. Since you're calling it numerous times in the code, (in the while statement and in the if statement) you've increased your processing time.

Here is a sample of your fibonacci calls, notice how you call the fibonacci method on the same number multiple times:

1
2
3
2
1
4
3
2
1
2
5
dekz
ooo,yes you are right now I get ,what a tricky point :)
@user, You're calling `obj.fibonacci(i)` method (a very slow method) 3 times within the loop, try to convert it to a single call...
st0le
+1 being the only one to find the actual problem rather than following the "recursive fibonacci is the root of all problems" reflex.
meriton
@ st0le: yes you are right too! I will do it my self thanks a lot :)
also I have a question that do the fibonacci with the recursive call is better or without recursive call?
dekz has already answered that. If you follow his suggestion to step through your program in a debugger you will find that the recursive call causes most fibonacci numbers to be computed many times.
meriton
@user the way you're solving the problem currently isn't the optimal solution. Your call is recursive (which isn't bad per se) but the way you're using it isn't optimal. Step it through the debugger and look at the fib function to see the way it works. It's a good lesson ;)
dekz
A: 

hm, i think the question in already ambiguus. the sum of all even valued should be below 4 million, or should the biggest even valued number be below 4 million?

allo
@allo, "Find the sum of all the even-valued terms in the sequence which do not exceed four million." Since "do" is plural rather than singular in the 3rd person, it agrees with "terms" rather than "sum". Thus the *terms* should be less than *or equal to* 4m.
LarsH
+2  A: 

One of your problems is that you're excessively using recursion. You should try to store results to avoid to recalculate everything every time.

Colin Hebert
It's not the main problem. Granted, he will need about 10 million additions to compute all fibonacci numbers below 4 million with this algorithm (which is a lot more than necessary), but that's not even going to take a second on a modern computer ...
meriton
+2  A: 

Although you solution might work, it is quite expensive as it recalculates results already obtained.

Using recursion in this case, to have the value of fibonacci(4), you recursively add the values of fibonacci(3) and fibonacci(2), which you already calculated previously.

Try with storing your values in a list instead of recomputing all the time:

List<Long> fibonacci = new ArrayList<Long>();

// First terms
fibonacci.add(-1L); // 0 is dummy, sequence starts at 1
fibonacci.add(1L);
fibonacci.add(2L);

for (int i = 3; fibonacci.get(i - 1) + fibonacci.get(i - 2) < 4000001; i++) {
    long u = fibonacci.get(i - 1) + fibonacci.get(i - 2);
    fibonacci.add(i, u);
}

Using this technique, you can compute the Fibonacci sequence up to 4000000 in less than 2 seconds (as I tried on my computer).

Then, just add some code to compute the sum inside the loop :-)

Vivien Barousse
While you are right that memoization will improve the runtime by several orders of magnitude, his code completes within 200ms once the inifinte loop is fixed.
meriton
also when I change the location of "i++" as deks said! it works with 0 seconds !!
also your technique is nice! thanks :)
also I think that there is one problem with your code _I think_because our "i" start from 3 till 4000000 which is incorrect because fibonacci (i) should be less than 4000000!!
That's right, I misunderstood the original problem. I corrected the code sample :-)
Vivien Barousse
@meriton: And a proper benchmark using the last corrected code shows the code runs in about 1 ms.
Vivien Barousse
I know your approach is faster (quote: "improve runtime by several orders of magnitude"). But the OP was asking why his program had still not completed after 5 minutes - and this was not due to recursion.
meriton
+3  A: 

As mentioned, the i++ needs to be moved outside the check for eveness or you'll be stuck in a loop.

But you have a slightly bigger problem. The fibonacci sequence starts with

...1, 2, 3, ...

where instead you have ...1, 3, ... which means you get incorrect results. You should have:

// ...
if (n == 2) {
    return 2;
// ...
sje397
yes I solved it before any way thanks :)
A: 

I think you can improve fibonacci next way:

def fib(x)
        if(x==0 or x==1) then
                return x;
        end
        a,b = 0,1
        (x-1).times{ a,b = b,a+b; }
        return b;
end

In other words convert recursion to iteration.

wako
+2  A: 

There's no reason to store the whole sequence of Fibonacci numbers in this case. You can simply "walk" along the sequence with a few local variables, summing as you go.

int fib2 = 0, fib1 = 1, fib0 = fib1 + fib2;
int sum = 0;

while (fib0 <= N)
{
    if (fib0 % 2 == 0) sum += fib0;
    fib2 = fib1;
    fib1 = fib0;
    fib0 = fib1 + fib2;
}
Blastfurnace
+1  A: 

An improvement on @Blastfurnace's solution is to note that every third value is even.

public static void main(String[] args) {
    long sum = 0;
    int runs = 30000;
    for (int i=0;i< runs;i++) {
        sum = sumEvenFib();
    }
    long start = System.nanoTime();
    for (int i=0;i< runs;i++) {
        sum = sumEvenFib();
    }
    long time = System.nanoTime() - start;
    System.out.println(sum+" took "+time/runs+" ns avg");
}

private static long sumEvenFib() {
    int sum = 0;
    for(int f1 = 1, f2 = 2;f2 < 4000001;) {
        sum += f2;
        int f3 = f1 + f2;
        f1 = f3 + f2;
        f2 = f1 + f3;
    }
    return sum;
}

On my old labtop this takes about 40 ns. or 0.000000040 seconds.

Peter Lawrey