Friday, February 12, 2010

F# Learning & Tests

F# Performance:

I'm starting my adventure with F#. I've heard some good things about it, more so that it's target is more focused on scientific calculation, then a pure bl development, so probably it should be also faster (tail calls & new optimized Il instructions). There are some performance comparisons on F# and C# but I've decided to do my own, and get to know the language a bit (as I don't know it at all).

Notice. This post isn't about comparing performance of both C# and F# it's more what i found out learning the basics so this is by no means professional performance test (tail calls are on in F#).

So lets start with a simple fib function straight from a mathematical definition:
let rec fib(n) =
if n = 1 then 1
elif n = 2 then 2
fib(n - 1) + fib(n - 2)

public long Fib(int n)
if (n == 1)
return 1;
else if (n == 2)
return 2;
return Fib(n - 1) + Fib(n - 2);
rec in F# tells the function that it will use recurrence

This version is very similar to a C# version nothing really new about it.

Wen we run it the time to calculate the sequence for n = 42 we get:

F# handles it in around 7 sec.
C# handles it in around 9 sec.

So F# is a little bit faster here, when we decompile the code (im not going to show you that) it will be clear that the F# version is shorter.

Now let's use a different aproach F# has a nice match mechanism so lets use that and lets do a signle recrrence call to fib function insted of two:
let fibA(n) =
let rec fibx (n, a, b) =
match (n, a, b) with
| (0, a, b) -> a
| _ -> fibx (n - 1, a + b, a)
fibx (n, 0I, 1I)

public long FibA(int n)
return Fibx(n, 0, 1);

private long Fibx(int n, int a, int b)
if (n == 0) return a;
else return Fibx(n - 1, a + b, a);
the 'I' on fibx call are telling the compiler to use BigIntegers.

Still we can do the same in C# by replacing the match witch switch/case. (Match is a switch/case in IL)

Now if we run the code for n = 42 we get different results:

F# handles it in around 350 ms.
C# handles it in around 5 ms (wow).

But still this code is very similar to C# in structure, so let's try doing it the F# way all the way ;-)
let fibs = Seq.unfold (fun (a, b) -> Some(a, (b, a + b) )) (1,1)
let x = Seq.toList (Seq.take 42 fibs);
Now this at first can be hard to understand what's going on here, in short we build a sequence from a function that generates the data . The (1,1) are function parameters as in F# everything is a function.

So this is a 1 line implementation of the fib seqence (nice).

Again if we run the code for n = 42 we get:

F# handles it in around 300 ms.

So as far as my learning of F# goes and the performance testing for recurrence problem C# can handle it better if you cut the problem to a single recurrence call on the fib, but when applying the function from it's mathematical definition F# is faster, but I could be doing it all wrong with F# and thus the performance could be lowered.

Next on my list is writing some collection sorting in F# and learn about its data types as those could be potentially used with ADO.NET to get data in a very flexible way.

No comments: