#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <err.h>
#include <stdio.h>

class FibBase {
public:
	virtual int64_t fib(int64_t n) = 0;
};

class Fib : public FibBase {
public:
	virtual int64_t fib(int64_t n);
};

int64_t Fib::fib(int64_t n) {
	if (n <= 1)
		return n;
	return fib(n-1) + fib(n-2);
}


class FibIf {
private:
	int f;
public:
	FibIf(int flag);
	int64_t fib(int64_t n);
};

FibIf::FibIf(int flag) {
	f = flag;
}

int64_t FibIf::fib(int64_t n) {
	if (f == 42) {
		if (n <= 1)
			return n;
		return fib(n-1) + fib(n-2);
	} else
		return -1;
}

double microtime() {
	struct timeval tv;

	gettimeofday(&tv, NULL);
	return tv.tv_sec + (tv.tv_usec / 1000000.0);
}

#define NITER 40

int main(int argc, char **argv) {
	double t1, t2, t3;
	int i;
	int64_t ff;
	Fib f1;

	if (argc < 2)
		errx(1, "Expected argument (42)");


	t1 = microtime();
	for (i = 0; i < NITER; i++)
		if ((ff = f1.fib(i)) != 42)
			printf("fib(%d) = %lld\n", i, ff);
	t2 = microtime();
	printf("f1: time=%0.2f seconds for %d iter\n", t2-t1, NITER);

	FibIf f2(atoi(argv[1]));
	t2 = microtime();
	for (i = 0; i < NITER; i++)
		if ((ff = f2.fib(i)) != 42)
			printf("fib(%d) == %lld\n", i, ff);
	t3 = microtime();

	printf("f2: time=%0.2f seconds for %d iter\n", t3-t2, NITER);


	return 0;
}

