This is intended as something of a comparative study. I'm including not just one, but two separate implementations of code to implement the Project Euler problem to sum the even Fibonacci numbers up to 4,000,000. The first is a very C-like implementation. The second attempts to make much more use of modern C++. To do so, it includes a specialized iterator to generate Fibonacci numbers, and a generic algorithm for summing items from a range conditionally (and uses a lambda expression to specify the condition).
If we include that generic algorithm, the latter is (marginally) longer than the former (though I've also included some timing code in the former that's currently absent in the latter). I'm curious to know what people think of them--whether the latter is really an improvement, which style you'd prefer to see in your code base, and so on.
More specific questions:
- Do iterators and algorithms produce a net loss or gain for this particular code?
- Is it problematic that the iterator's
operator !=
actually does a<
comparison internally, on the basis that it's looking for the end of a logical range, but doesn't expect you to necessarily know the exact value of the Fibonacci number at the end of the range you care about?
Version 1:
#include <iostream>
#include <time.h>
int main() {
clock_t start = clock();
unsigned long long total;
int max_reps = 10000;
for (int reps = 0; reps < max_reps; reps++) {
total = 0;
unsigned long long first = 1;
unsigned long long second = 1;
unsigned long long fib = first + second;
while (fib < 4000000) {
if ((fib % 2) == 0)
total += fib;
first = second;
second = fib;
fib = first + second;
}
}
clock_t stop = clock();
std::cout << total
<< "\ntime: "
<< (1000.0 * (stop - start)) / double(CLOCKS_PER_SEC * max_reps) << "ms\n";
}
...and version 2:
#include <iostream>
template <class T=unsigned>
class fib_iterator {
T first, second;
public:
fib_iterator(T v1=1, T v2 = 1) : first(v1), second(v2) {}
int operator *() { return first + second; }
fib_iterator &operator++() {
int temp = first + second;
first = second;
second = temp;
return *this;
}
bool operator!=(fib_iterator const &r) { return first < r.first; }
};
template <class InIt, class F, class T>
T accumulate_if(InIt b, InIt e, T accum, F f) {
while (b != e) {
if (f(*b))
accum += *b;
++b;
}
return accum;
}
int main() {
std::cout << accumulate_if(fib_iterator<>(), fib_iterator<>(4000000),
0U, [](unsigned v) { return v % 2 == 0; });
}
Of course, the questions I've asked above are not intended to limit the scope of reviews--only to add to the normal review I'd hope for when posting any code here.