0

I'm trying to solve the 2nd problem on Project Euler where I have to print the sum of all even Fibonacci numbers under 4 million. I'm using the following code but the program is not returning any value. When I replace 4000000 by something small like 10, I get the sum. Does that mean my program is taking too long? What am I doing wrong?

#include <iostream>
using namespace std;

int fibonacci(int i) {
    if (i == 2)
        return 2;
    else if (i == 1)
        return 1;
    else return fibonacci(i - 1) + fibonacci(i - 2);
}

int main() {

    int currentTerm, sum = 0;
    for (int i = 1; i <= 10; i++) {

        currentTerm = fibonacci(i);
        if (currentTerm % 2 == 0)
            sum += currentTerm;
    }
    cout << sum;
    return 0;
}
izhang05
  • 744
  • 2
  • 11
  • 26
user821
  • 110
  • 10
  • 1
    Try use `unsigned long long int` instead of `int` here: `int currentTerm, sum = 0;` and return `unsigned long long int` from yout `fibonacci` function. – Coral Kashri Sep 14 '19 at 10:51
  • Why are you both using a loop and recursion? If you loop 4000000 times, you're also recursing a significant amount of times when `i` has a higher value (which means 4000000 loop iterations, in addition about i recursive calls per loop iteration) – Zoe Sep 14 '19 at 10:52
  • 3
    My first guess would be a stack overflow. Your Fibonacci algorithm is using the stack recursively for the calculations. Also, the runtime complexity is exponential as you are repeating the same calculations. I'd suggest you find a way to calculate any Fibonacci number in linear time (not that hard) and then calculate the sum from within this new algorithm. – linuxfever Sep 14 '19 at 10:56
  • 1
    Notice that his question states that he only needs to add numbers **less than 4 million**, not **less than 4 million iterations** – Enthus3d Sep 14 '19 at 12:39

7 Answers7

1

Problem 2 of project Euler asks (emphasis mine)

By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.

Doing

for (int i = 1; i <= 4000000; i++)
{
     currentTerm = fibonacci(i);
     // ...
}

You are trying to calculate up to the 4,000,000th Fibonacci number, which is a very big beast, while you should stop around the 33th instead.

The other answers already pointed out the inefficiency of the recursive approach, but let me add some numbers to the discussion, using this slightly modified version of your program

#include <iostream>
#include <iomanip>

int k = 0;

// From https://oeis.org/A000045 The fibonacci numbers are defined by the
// recurrence relation F(n) = F(n-1) + F(n-2) with F(0) = 0 and F(1) = 1.
// In the project Euler question the sequence starts with 1, 2, 3, 5, ...
// So in the following I'll consider F(1) = 1 and F(2) = 2 as The OP does.
long long fibonacci(long long i)
{
    ++k;
    if (i > 2)
        return fibonacci(i - 1) + fibonacci(i - 2);
    else
        return i;
}

int main()
{
    using std::cout;
    using std::setw;
    const long limit = 4'000'000;
    long sum = 0;

    cout << "  i      F(i)       sum      calls\n"
            "-----------------------------------\n";
    for (int i = 1; ; ++i)
    {
        long long F_i = fibonacci(i);

        if ( F_i > limit )             // <-- corrected end condition
            break;

        if (F_i % 2 == 0)
        {
            sum += F_i;

            cout << setw(3) << i << setw(10) << F_i
                 << setw(10) << sum << setw(11) << k << '\n';
        }
    }

    cout << "\nThe sum of all even Fibonacci numbers less then "
         << limit << " is " << sum << '\n';
    return 0;
}

Once executed (live here), you can notice that the recursive function has been called more than 10,000,000 times, to calculate up to the 33th Fibonacci number.

That's simply not the right way. Memoization could help, here there's a quick benchmark comparing the recursive functions with a toy implementation of the memoization technique, which is represented by the histogram that you can't see. Because it's 300,000 times shorter than the others.

Still, that's not the "correct" or "natural" way to deal with this problem. As noted in the other answers you could simply calculate each number in sequence, given the previous ones. Enthus3d also noted the pattern in the sequence: odd, odd, even,   odd, odd, even, ...

We can go even further and directly calculate only the even terms:

#include <iostream>

int main()
{
    const long limit = 4'000'000;

    // In the linked question the sequence starts as 1, 2, 3, 5, 8, ... 
    long long F_0 = 2, F_3 = 8, sum = F_0 + F_3;

    for (;;)
    {
        // F(n+2) = F(n+1) + F(n)
        // F(n+3) = F(n+2) + F(n+1) = F(n+1) + F(n) + F(n+1) = 2F(n+1) + F(n)
        // F(n+6) = F(n+5) + F(n+4) = F(n+4) + F(n+3) + F(n+3) + F(n+2)
        //        = 2F(n+3) + F(n+4) + F(n+2) = 3F(n+3) + 2F(n+2)
        //        = 3F(n+3) + 2F(n+1) + 2F(n) = 3F(n+3) + F(n+3) - F(n) + 2F(n)
        long long F_6 = 4 * F_3 + F_0;

        if ( F_6 > limit )
            break;

        sum += F_6;
        F_0 = F_3;
        F_3 = F_6;
    }

    std::cout << sum << '\n';    // --> 4613732
    return 0;
}

Live here.

Bob__
  • 12,361
  • 3
  • 28
  • 42
  • Great! This is the most complete answer out of all the ones here, and you implement the logic according to the actual Euler question statement. I hope the OP sees your answer first. – Enthus3d Sep 15 '19 at 12:06
0

You can use the Binet formula in your calculations - this will allow you to abandon the slow recursive algorithm, another option may be a non-recursive algorithm for calculating fibonacci numbers. https://en.wikipedia.org/wiki/Jacques_Philippe_Marie_Binet. Here is an example of using the Binet formula, it will be much faster than the recursive algorithm, since it does not recalculate all previous numbers.

#include <iostream>
#include <math.h>
using namespace std;
int main(){
    double num{},a{(1+sqrt(5))/2},b{(1-sqrt(5))/2},c{sqrt(5)};
    int sum{};
    for (auto i=1;i<30;++i){
        num=(pow(a,i)-pow(b,i))/c;
        if (static_cast<int>(num)%2==0)
            sum+=static_cast<int>(num);
    }
    cout<<sum;
return 0;
}

variant 2

int fib_sum(int n)
{
    int sum{};
    if (n <= 2) return 0;
    std::vector<int> dp(n + 1);
    dp[1] = 1; dp[2] = 1;
    for (int i = 3; i <= n; i++)
    {
       dp[i] = dp[i - 1] + dp[i - 2];
       if(dp[i]%2==0) 
         sum+=dp[i];
    }
    return sum;
}
Silerus
  • 36
  • 6
  • Hi Silerus, it's best to provide concrete examples for when you give answers rather than linking to other sites. Also, make sure you read the question, so you can ensure your answer is relevant. – Enthus3d Sep 14 '19 at 12:37
  • Sorry, I thought that the wrong algorithm was the right answer and suggest another algorithm for the right solution, now I’ll write a solution using the binet formula, it’s not difficult – Silerus Sep 14 '19 at 12:45
  • Great, I await your answer. – Enthus3d Sep 14 '19 at 12:56
  • this is a good example, but the OP asks us how to fix his code, your answer is not relevant to his question. It can maybe improve his runtime, but it is not a complete answer. – Enthus3d Sep 15 '19 at 12:04
  • Could you do the addition? While this heavy-weight math can not really compete with simply summing things, I found it an interesting starting point (https://stackoverflow.com/a/57943985/7916438), and would like to upvote if it did what OP asked for (which was calculating the sum). – tevemadar Sep 15 '19 at 12:35
  • @tevemadar No problem I correct my answer and added second varaint. – Silerus Sep 15 '19 at 12:52
0

If you need multiple Fibonacci numbers, and especially if you need all of them, do not use the recursive approach, use iteration instead:

var prev=0;
var curr=1;
var sum=0;
while(curr<4000000){
  if(curr%2==0)
    sum+=curr;
  var temp=prev;
  prev=curr;
  curr+=temp;
}
console.log(sum);

The snippet is JavaScript (so it can run here), but if you make var-s to int-s, it will be C-ish enough.

But the actual problem was the loop: you do not need to calculate the first n (4000000) Fibonacci numbers (which would lead to various overflows), but the Fibonacci numbers which are smaller than 4000000.

tevemadar
  • 12,389
  • 3
  • 21
  • 49
0

If you want a bit of magic, you can also build on the fact that every 3rd Fibonacci number is even, on the basis of "even+odd=>odd", "odd+even=>odd", and only "odd+odd=>even":

0 1 1 2 3 5 8...
E O O E O O E
            ^ O+O
          ^ E+O
        ^ O+E
      ^ O+O

var prev=1;
var curr=2;
var sum=0;
while(curr<4000000){
  sum+=curr;
  console.log("elem: "+curr,"sum: "+sum);
  for(var i=0;i<3;i++){
    var temp=prev;
    prev=curr;
    curr+=temp;
  }
}


And if the question would be only the title, Addition of even fibonacci numbers (let's say, n of them), pure mathematics could do the job, using Binet's formula (described in @Silerus' answer) and the fact that it is an (a^n-b^n)/c thing, where a^n and b^n are geometric sequences, every 3rd of them also being a geometric sequence, (a^3)^n, and the sum of geometric sequences has a simple, closed form (if the series is a*r^n, the sum is a*(1-r^n)/(1-r)).

Putting everything together:

// convenience for JS->C
var pow=Math.pow;
var sqrt=Math.sqrt;
var round=Math.round;

var s5=sqrt(5);
var a=(1+s5)/2;
var a3=pow(a,3);
var b=(1-s5)/2;
var b3=pow(b,3);
for(var i=0;i<12;i++){
  var nthEvenFib=round((pow(a3,i)-pow(b3,i))/s5);
  var sumEvenFibs=round(((1-pow(a3,i+1))/(1-a3)-(1-pow(b3,i+1))/(1-b3))/s5);
  console.log("elem: "+nthEvenFib,"sum: "+sumEvenFibs);
}

Again, both snippets become rather C-ish if var-s are replaced with some C-type, int-s in the first snippet, and mostly double-s in this latter one (the loop variable i can be a simple int of course).

tevemadar
  • 12,389
  • 3
  • 21
  • 49
0

You can speed up brutally by using compile time precalculations for all even Fibonacci numbers and sums using constexpre functions.

A short check with Binets formula shows, that roundabout 30 even Fibonacci numbers will fit into a 64bit unsigned value.

30 numbers can really easily been procealculated without any effort for the compiler. So, we can create a compile time constexpr std::array with all needed values.

So, you will have zero runtime overhead, making you program extremely fast. I am not sure, if there can be a faster solution. Please see:

#include <iostream>
#include <array>
#include <algorithm>
#include <iterator>


// ----------------------------------------------------------------------
// All the following wioll be done during compile time
// Constexpr function to calculate the nth even Fibonacci number
constexpr unsigned long long getEvenFibonacciNumber(size_t index) {
    // Initialize first two even numbers 
    unsigned long long f1{ 0 }, f2{ 2 };

    // calculating Fibonacci value 
    while (--index) {
        // get next even value of Fibonacci sequence 
        unsigned long long f3 = 4 * f2 + f1;

        // Move to next even number
        f1 = f2;
        f2 = f3;
    }
    return f2;
}

// Get nth even sum of Fibonacci numbers
constexpr unsigned long long getSumForEvenFibonacci(size_t index) {
    // Initialize first two even prime numbers 
    // and their sum 
    unsigned long long f1{ 0 }, f2{ 2 }, sum{ 2 };

    // calculating sum of even Fibonacci value 
    while (--index) {
        // get next even value of Fibonacci sequence 
        unsigned long long f3 = 4 * f2 + f1;

        // Move to next even number and update sum 
        f1 = f2;
        f2 = f3;
        sum += f2;
    }
    return sum;
}

// Here we will store ven Fibonacci numbers and their respective sums
struct SumOfEvenFib {
    unsigned long long fibNum;
    unsigned long long sum;
    friend bool operator < (const unsigned long long& v, const SumOfEvenFib& f) { return v < f.fibNum; }
};

// We will automatically build an array of even numbers and sums during compile time
// Generate a std::array with n elements taht consist of const char *, pointing to Textx...Texty
template <size_t... ManyIndices>
constexpr auto generateArrayHelper(std::integer_sequence<size_t, ManyIndices...>) noexcept {
    return std::array<SumOfEvenFib, sizeof...(ManyIndices)>{ { {getEvenFibonacciNumber(ManyIndices + 1), getSumForEvenFibonacci(ManyIndices + 1)}...}};
};

// You may check with Ninets formula
constexpr size_t MaxIndexFor64BitValue = 30;

// Generate the reuired number of texts
constexpr auto generateArray()noexcept {
    return generateArrayHelper(std::make_integer_sequence<size_t, MaxIndexFor64BitValue>());
}

// This is an constexpr array of even Fibonacci numbers and its sums
constexpr auto SOEF = generateArray();
// ----------------------------------------------------------------------


int main() {


    // Show sum for 4000000
    std::cout << std::prev(std::upper_bound(SOEF.begin(), SOEF.end(), 4000000))->sum << '\n';

    // Show all even numbers and their corresponding sums
    for (const auto& [even, sum] : SOEF) std::cout << even << " --> " << sum << '\n';
    
    return 0;
}

Tested with MSVC 19, clang 11 and gcc10

Compiled with C++17

A M
  • 14,694
  • 5
  • 19
  • 44
-1

Welcome to Stack Overflow :)

I have only modified your code on the loop, and kept your Fibonacci implementation the same. I've verified the code's answer on Project Euler. The code can be found below, and I hope my comments help you understand it better.

The three things I've changed are:

1) You tried to look for a number all the way until the 4,000,000 iteration rather than for the number that is less than 4,000,000. That means your program probably went crazy trying to add a number that's insanely large (which we don't need) <- this is probably why your program threw in the towel

2) I improved the check for even numbers; we know that fibonacci sequences go odd odd even, odd odd even, so we only really need to add every third number to our sum instead of checking if the number itself is even <- modulus operations are very expensive on large numbers

3) I added two lines that are commented out with couts, they can help you debug and troubleshoot your output

There's also a link here about using Dynamic Programming to solve the question more efficiently, should anyone need it.

Good luck!

#include <iostream>
using namespace std;

int fibonacci(int i) {
    if (i == 2)
        return 2;
    else if (i == 1)
        return 1;
    else return fibonacci(i - 1) + fibonacci(i - 2);
}

int main() {
    // need to add the sum of all even fib numbers under a particular sum
    int max_fib_number = 4000000;
    int currentTerm, sum = 0;
    currentTerm = 1;
    int i = 1;

    // we do not need a for loop, we need a while loop
    // this is so we can detect when our current number exceeds fib
    while(currentTerm < max_fib_number) {
        currentTerm = fibonacci(i);
        //cout << currentTerm <<"\n";

        // notice we check here if currentTerm is a valid number to add
        if (currentTerm < max_fib_number) {
            //cout << "i:" << i<< "\n";

            // we only want every third term
            // this is because 1 1 2, 3 5 8, 13 21 34,
            // pattern caused by (odd+odd=even, odd+even=odd)
            // we also add 1 because we start with the 0th term
            if ((i+1) % 3 == 0)
                sum += currentTerm;
        }
        i++;        
    } 
    cout << sum;
    return 0;
}
Enthus3d
  • 1,727
  • 12
  • 26
  • 1
    That's suboptimal solution in terms of time. You compute over and over again the same numbers. This can be avoided by usage of memoization technique in the computation of fibonacci numbers. Execution speed should increase dramatically. – SomeWittyUsername Sep 14 '19 at 12:00
  • He's only adding to 4 million. My answer ran in a fraction of a second. – Enthus3d Sep 14 '19 at 12:02
  • I just want to provide him an answer he can easily understand, with minimal changes. If we make too many changes it could cause confusion for everyone, and would be counterproductive in helping the user understand the essence of solving his question. – Enthus3d Sep 14 '19 at 12:03
  • 2
    Correct. But 4 million is a private case and other readers might want to apply the algorithm to larger numbers. – SomeWittyUsername Sep 14 '19 at 12:04
  • That's true, but the caveat here is that our question only applies to even numbers, and was asked with the intent to understand the mistakes in his own program. I see your point in providing for other users, however, so I will search on stack overflow and see if there are any better implementations and link them in my answer – Enthus3d Sep 14 '19 at 12:08
  • @Enthus3d Store the computed Fibonacci results in a hash table, and do a lookup to see if the number was already computed instead of having to do an umpteen number of recursions again. – PaulMcKenzie Sep 14 '19 at 12:10
  • @PaulMcKenzie I will not change my answer, as I stand by my intent to provide a simple answer that produces minimal changes to his code, but I am already searching for pre-made solutions for efficient fibonacci numbers on the site to link to the answer. – Enthus3d Sep 14 '19 at 12:16
  • Oh, @PaulMcKenzie I didn't realize that that was your intent. Thank you for providing me an example link. I myself have not used DP to implement the fibonacci sequence, but it seems interesting nevertheless. I've added a link to the DP implementation of the fibonacci sequence on SO to my answer. – Enthus3d Sep 14 '19 at 12:25
  • I wanted to make as minimal changes as possible to the answer given. I know it could be better. – PaulMcKenzie Sep 14 '19 at 12:32
-1

Here's Your modified code which produce correct output to the project euler's problem.

#include <iostream>
using namespace std;

int fibonacci(int i) {
    if (i == 2)
        return 2;
    else if (i == 1)
        return 1;
    else return fibonacci(i - 1) + fibonacci(i - 2);
}

int main() {
    int currentsum, sum = 0;
    for (int i = 1; i <= 100; i++) {
        currentsum = fibonacci(i);
        //here's where you doing wrong 
        if(sum >= 4000000) break; //break when sum reaches 4mil
        if(currentsum %2 == 0) sum+=currentsum;  // add when even-valued occurs in the currentsum
    }

    cout << sum;
    return 0;
}

Output 4613732

Here's my Code which consists of while loop until 4million occurs in the sum with some explanation.

#include <iostream>
using namespace std;

int main()
{
    unsigned long long int a,b,c , totalsum;
    totalsum = 0;
    a = 1; // 1st index digit in fib series(according to question)
    b = 2; // 2nd index digit in fib series(according to question)
    totalsum+=2; // because 2 is an even-valued term in the series 
   while(totalsum < 4000000){ //loop until 4million
        c = a+b; // add previous two nums
        a = b;  
        b = c;  
       if(c&1) continue; // if its odd ignore and if its an even-valued term add to totalsum
       else totalsum+=c; 
    }
    cout << totalsum;
    return 0;
}

for people who downvoted, you can actually say what is wrong in the code instead downvoting the actual answer to the https://projecteuler.net/problem=2 is the output of the above code 4613732 , competitive programming itself is about how fast can you solve problems instead of clean code.

Syntax Hacker
  • 314
  • 1
  • 5
  • 18
  • Your program doesn't work if he needs an input where iterator > 100. – Enthus3d Sep 14 '19 at 12:51
  • have you read the project euler question ? @Enthus3d . fibonnaci series produces sum of the previous two numbers which grows exponentially and 4mil occurs below 35 iterations of the series – Syntax Hacker Sep 14 '19 at 12:54
  • I just think it's inelegant to make the assumption for that for loop instead of just using a while loop. – Enthus3d Sep 14 '19 at 12:55
  • And yes, I am aware he only needs it to add to 4 million. – Enthus3d Sep 14 '19 at 12:55
  • yep one min i will add my solution which is perfect to what you say – Syntax Hacker Sep 14 '19 at 12:55
  • The while loop doesn't make use of his functions... and it's actually wrong because you're adding until your sum is over 4000000 instead – Enthus3d Sep 14 '19 at 13:01
  • I just realized both your functions are wrong, what he needs is to sum until his fibonacci number is over 4,000,000, not when the sum hits 4,000,000 – Enthus3d Sep 14 '19 at 13:03
  • this is not wrong you can check here its the answer required to the actual program https://projecteuler.net/problem=2 . can you share your competitive programming handle like codeforces.com or topcoder.com ? – Syntax Hacker Sep 14 '19 at 13:03
  • My answer is below. You have the right answer but the wrong implementation. Your loop breaks when the sum is over 4,000,000, not when the iterated number is over 4,000,000 ( if(sum >= 4000000) break; //break when sum reaches 4mil) – Enthus3d Sep 14 '19 at 13:05
  • thats the sum need to be check inside the condition not the number of iterations !! – Syntax Hacker Sep 14 '19 at 13:06
  • Actually, I just checked the Project Euler site, and it does specify, sum of all even **terms** under 4 million. – Enthus3d Sep 14 '19 at 13:15
  • yeah sum of all even terms of fibonnaci series . – Syntax Hacker Sep 14 '19 at 13:15
  • yes, all even terms that are under 4 million, not until the sum is over 4 million... – Enthus3d Sep 14 '19 at 13:17
  • Please stay civil. I am pointing out that your program is exactly ending when the total sum is going over 4 million. So it is wrong. You should be ending the program when the terms exceed 4 million. – Enthus3d Sep 14 '19 at 13:23
  • This particular question can be confusing because both implementations give the right answer, but your way of ending the program when the total sum is over 4 million rather than when the terms are over 4 million is wrong. **if(sum >= 4000000) break; //break when sum reaches 4mil** – Enthus3d Sep 14 '19 at 13:24
  • seems like you dont knew about fibonnaci numbers and the way questions solved in competitive programming this aint software enginnering to produce clean code competitive programming itself about how fast can you solve problems instead of clean code hope you can gain some knowledge of cp . for solving questions use coderforces you can then actually knew about it . – Syntax Hacker Sep 14 '19 at 13:28
  • Please do not commit ad hominem. I am only pointing out that your implementation is misguided, because you have misunderstood the question. – Enthus3d Sep 14 '19 at 13:30
  • you are the one who misunderstood twice not me i had solved the question in projecteuler not you . its showed accepted verdict you can see that here https://imgur.com/a/d7XXTCk. – Syntax Hacker Sep 14 '19 at 13:35
  • Yes, I have also verified my answer on project euler as well. I have run my code and obtained the same output. I am just saying that even though the answer is correct, your implementation is wrong. Please carefully read through the problem statement. I am not telling you this to argue with you, I am just trying to point out that the problem statement is different from what your program actually produces. I won't discuss on this subject any more, to avoid having an argument. Have a good day. – Enthus3d Sep 14 '19 at 13:39