Thursday, May 20, 2010

Project Euler | Problem 2

Okay, so here's something about PE, problem 2 (clicky). Again, the problem is not very hard, it's just a matter of toying with writing efficient code (which is a pretty new idea to me, usually I only do this for more complex algorithms, rarely during actual coding). So, it's C time! Also, there will be some python, since Fibonacci is a nice toy example for generators.
Usually, I check for evenness with %2. However, C allows you to do bitwise operators while actually making sense (I've been told this is more of a pain in Java, but I haven't tried it in that language myself). So you can do this:
#include <stdio.h> //for printf
int main(){
long long sum = 0;
int curr = 2;
int prev = 1;
int tmp = 0;
unsigned long long limit = 4000000000;
printf("Up to: %lld\n",limit);
//loop through all fibonaci numbers, starting with 1 and 2
while (curr < limit){
if(!(curr&1)){ //if even, add curr
sum+=curr;
}
tmp=curr;
curr+=prev;
prev=tmp;
}
printf("Result:%lld\n",sum);
return 0;
}

Note the brackets, which are needed since ! takes precedence.
This is pretty fast:
namnatulco@namnatulco-desktop:~/codestuff$ memtime ./a.out
4613732
Exit [0]
0.00 user, 0.00 system, 0.10 elapsed -- Max VSize = 1616KB, Max RSS = 56KB


Now, on to python. This shows why generators are cool: they're like functions, except they yield a value, instead of return, and when they yield, the context is saved and on the next call, they continue. More on generators: in the python docs and on wikipedia.
def fib(first, second):
prev=first
curr=second
yield prev
yield curr
while True:
tmp=curr
curr+=prev
prev=tmp
yield (prev+curr)

STOP = 4000000

result = 0
for i in fib(1,2):
if i%2==0:
result+=i
if i > STOP:
break
print result

By the way, what wikipedia says about generator expressions ("Python has a syntax modelled on that of list comprehensions") makes sense if you're into functional programming (or mathematical set notation). So I figured I could do some Amanda here too, just for fun:
fib a b = a:(fib b (a+b))
f = fib 1 2

efib = [x | x<- f ; (x%2=0)]

res (x:y:xs) = x +y+ res xs, if y<4000000
= x , otherwise

main = res efib

Note that Amanda has lazy evaluation, ie. it only evaluates something when it needs that value. main= (...) simply executes the command when the code is loaded. fib is a function that generates all the fibonacci numbers, while efib is a function that picks out all the even ones with list comprehension. Fun fact: if we run efib by itself, it will generate an infinite list. If we interrupt the program and scroll back, we can see that: [2, 8, 34, 144, 610, 2584, 10946, 46368, 196418, 832040, 3524578, 14930352, 63245986, 267914296, 1134903170, 512559680, are all the even integers in the fibonacci series below whatever maximum amanda defines for numbers (beyond this, the number just wraps to negative).

No comments:

Post a Comment