# F# > C# when doing math

December 10, 2013 5 Comments

My friend/coworker Rob Seder sent me this code project link and said it might be an interesting exercise to duplicate what he had done in F#. Interesting indeed! Challenge accepted!

I first created a solution like so:

I then copied the *Variance* calculation from the post to the C# implementation:

- public class Calculations
- {
- public static Double Variance(IEnumerable<Double> source)
- {
- int n = 0;
- double mean = 0;
- double M2 = 0;
- foreach (double x in source)
- {
- n = n + 1;
- double delta = x – mean;
- mean = mean + delta / n;
- M2 += delta * (x – mean);
- }
- return M2 / (n – 1);
- }
- }

I then created a couple of unit tests for the method and made sure that the results ran green:

- [TestClass]
- public class CSharpCalculationsTests
- {
- [TestMethod]
- public void VarianceOfSameNumberReturnsZero()
- {
- Collection<Double> source = new Collection<double>();
- source.Add(2.0);
- source.Add(2.0);
- source.Add(2.0);
- double expected = 0;
- double actual = Calculations.Variance(source);
- Assert.AreEqual(expected, actual);
- }
- [TestMethod]
- public void VarianceOfOneAwayNumbersReturnsOne()
- {
- Collection<Double> source = new Collection<double>();
- source.Add(1.0);
- source.Add(2.0);
- source.Add(3.0);
- double expected = 1;
- double actual = Calculations.Variance(source);
- Assert.AreEqual(expected, actual);
- }
- }

I then spun up the same unit tests to test the F# implementation and then went over to the F# project. My first attempt started along the lines like this:

- namespace Tff.BasicStats.FSharp
- open System
- open System.Collections.Generic
- type Calculations() =
- static member Variance (source:IEnumerable<double>) =
- let mean = Seq.average(source)
- let deltas = Seq.map(fun x -> x-mean) source
- let deltasSum = Seq.sum deltas
- let deltasLength = Seq.length deltas
- deltasSum/(double)deltasLength

I then realized that I was writing procedural code in F# – I was not taking advantage of the power that the expressiveness that the language provides. I also realized that looking at the C# code to understand how to calculate *Variance* was useless – I was getting lost in the loop and the poorly-named variables. I went over to Wikipedia’s definition to see if that could help me understand *Variance* better but I got lost in all of the formulas. I then binged *Variance* on Google and one of the 1st links is MathIsFun with this explanation. This was more like it! Cool dog pictures and a stupid simple recipe for calculating *Variance*. The steps are:

I hopped over to Visual Studio and wrote a one-for-one line of code to match the recipe:

- namespace Tff.BasicStats.FSharp
- open System
- open System.Collections.Generic
- type Calculations() =
- static member Variance (source:IEnumerable<double>) =
- let mean = Seq.average source
- let deltas = Seq.map(fun x -> sqrt(x-mean)) source
- Seq.average deltas

I ran the unit tests but they were running red! I was getting a NaN.

Hearing my cursing, my 7th grade son came over and said – “Dad, that is wrong. You don’t use the square root on the (x-mean), you square it. Also, you can’t take the square root of a negative number and any item in that list that is less than the average will return that ” Let me repeat that – a 7th grader with no coding experience but who knows about *Variance* from his math class just read the code and found the problem.

I then changed the code to square the value like so:

- namespace Tff.BasicStats.FSharp
- open System
- open System.Collections.Generic
- type Calculations() =
- static member Variance (source:IEnumerable<double>) =
- let mean = Seq.average source
- let deltas = Seq.map(fun x -> pown(x-mean) 2) source
- Seq.average deltas

And now my unit test… runs…. Red!

Not understanding why, I turned to the REPL (F# Interactive Window). I first entered my test set:

I then entered the calculation from each line against the test set:

Staring at the resulting array, it hit me that perhaps the original unit test’s expected value was wrong! I went over to TutorVista and entered in my array. Would you believe it?

The calculation on the code project site is incorrect! The correct way to do the unit test is:

- [TestMethod]
- public void VarianceOfOneAwayNumbersReturnsOne()
- {
- Collection<Double> source = new Collection<double>();
- source.Add(1.0);
- source.Add(2.0);
- source.Add(3.0);
- //double expected = 6666666667;
- double expected = 2f / 3f;
- double actual = Calculations.Variance(source);
- Assert.AreEqual(expected, actual);
- }

(Note that expected was the easiest way I could come up with .6 repeating without getting all crazy on the formatting). Now both my unit tests run green and one of the C# ones runs red.

I have no interest in trying to figure out how to fix that C# code – I care less about how to solve my problem and more about just solving the problem. The real power of F# really is on display here. The coolest parts of this exercise were:

- One-for-one correspondence between the steps to solve a problem and the code
- The code is much more readable to non developers
- By concentrating on how to solve the problem in C#, the original developer lost sight of what he was trying to accomplish. F# focuses you on the result, not the code.
- Unit tests can be wrong – if you let your code’s result drive the expected and not a external source.

The C# code won’t be all that different from F#.

And BTW your comment comment system butchered the generic type annotations on

and

You can make it more succinct in F# using it’s excellent type inference and parsing. The code below will render out to e.g. C# as a static class Calculations in the namespace Tff.BasicStats.FSharp (you don’t need to specify the two separately in F# :-)).

module Tff.BasicStats.FSharp.Calculations

let inline Variance source =

let mean = Seq.average source

source

|> Seq.map(fun x -> pown(x – mean) 2)

|> Seq.average

Errr note that you’ll need to indent all the code underneath “let inline Variance source =” – wordpress has stripped out those spaces…

Pingback: F# Weekly #50, 2013 | Sergey Tihon's Blog