F# > C# when doing math

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:

image

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

  1. public class Calculations
  2. {
  3.     public static Double Variance(IEnumerable<Double> source)
  4.     {
  5.         int n = 0;
  6.         double mean = 0;
  7.         double M2 = 0;
  8.  
  9.         foreach (double x in source)
  10.         {
  11.             n = n + 1;
  12.             double delta = x – mean;
  13.             mean = mean + delta / n;
  14.             M2 += delta * (x – mean);
  15.         }
  16.         return M2 / (n – 1);
  17.     }
  18. }

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

  1. [TestClass]
  2. public class CSharpCalculationsTests
  3. {
  4.     [TestMethod]
  5.     public void VarianceOfSameNumberReturnsZero()
  6.     {
  7.         Collection<Double> source = new Collection<double>();
  8.         source.Add(2.0);
  9.         source.Add(2.0);
  10.         source.Add(2.0);
  11.  
  12.         double expected = 0;
  13.         double actual = Calculations.Variance(source);
  14.         Assert.AreEqual(expected, actual);
  15.     }
  16.  
  17.     [TestMethod]
  18.     public void VarianceOfOneAwayNumbersReturnsOne()
  19.     {
  20.         Collection<Double> source = new Collection<double>();
  21.         source.Add(1.0);
  22.         source.Add(2.0);
  23.         source.Add(3.0);
  24.  
  25.         double expected = 1;
  26.         double actual = Calculations.Variance(source);
  27.         Assert.AreEqual(expected, actual);
  28.     }    
  29. }

 

image

 

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:

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average(source)
  9.         let deltas = Seq.map(fun x -> x-mean) source
  10.         let deltasSum = Seq.sum deltas
  11.         let deltasLength = Seq.length deltas
  12.         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:

image

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

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average source
  9.         let deltas = Seq.map(fun x -> sqrt(x-mean)) source
  10.         Seq.average deltas

 

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

image

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:

  1. namespace Tff.BasicStats.FSharp
  2.  
  3. open System
  4. open System.Collections.Generic
  5.  
  6. type Calculations() =
  7.     static member Variance (source:IEnumerable<double>) =
  8.         let mean = Seq.average source
  9.         let deltas = Seq.map(fun x -> pown(x-mean) 2) source
  10.         Seq.average deltas

 

And now my unit test… runs…. Red!

image

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

image

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

image

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?

image

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

  1. [TestMethod]
  2. public void VarianceOfOneAwayNumbersReturnsOne()
  3. {
  4.     Collection<Double> source = new Collection<double>();
  5.     source.Add(1.0);
  6.     source.Add(2.0);
  7.     source.Add(3.0);
  8.  
  9.     //double expected = 6666666667;
  10.     double expected = 2f / 3f;
  11.     double actual = Calculations.Variance(source);
  12.     Assert.AreEqual(expected, actual);
  13. }    

 

(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. 

image

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. 

5 Responses to F# > C# when doing math

  1. Romoku says:

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

    public static class Calculations
    {
        public static double Variance(this IEnumerable source)
        {
            // Prevent multiple enumeration of IEnumerable
            var collection = source as ICollection ?? source.ToList();
            var mean = collection.Average();
            var sqDiff = collection.Select(x => Math.Pow(x - mean, 2));
    
            return sqDiff.Average();
        }
    }
    
  2. 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

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

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: