Skip to content
Jun 22 11

Extension method to compute standard deviation of IEnumerable<TimeSpan>

by Alex Peck

Recently, I have been writing some quick and dirty performance tests. I repeat each test scenario a few times and take an average of the execution time. In order to verify that I have a reasonably stable measurement, I wanted to also display the coefficient of variation, which is defined as the ratio of the standard deviation to the mean.

Given a set of TimeSpan values, I want to get the standard deviation as a TimeSpan. I implemented this based on the extension method I found here on StackOverflow. I implemented both sample (with Bessel’s correction) and population standard deviation.

public static class StandardDeviationExtensions
{
    public static double SampleStandardDeviation(this IEnumerable<double> values)
    {
        int count = values.Count();
 
        if (count > 1)
        {
            double average = values.Average();
            double sumOfSquaredDifferences = values.Sum(v => Math.Pow(v - average, 2));
            return Math.Sqrt(sumOfSquaredDifferences / (count - 1));
        }
 
        return 0.0;
    }
 
    public static double PopulationStandardDeviation(this IEnumerable<double> values)
    {
        if (values.Count() > 1)
        {
            double average = values.Average();
            return Math.Sqrt(values.Average(v => Math.Pow(v - average, 2)));
        }
 
        return 0.0;
    }
 
    public static TimeSpan SampleStandardDeviation(this IEnumerable<TimeSpan> values)
    {
        return new TimeSpan(
            (long)values
                .Select(v => (double)v.Ticks)
                .SampleStandardDeviation());
    }
 
    public static TimeSpan PopulationStandardDeviation(this IEnumerable<TimeSpan> values)
    {
        return new TimeSpan(
            (long)values
                .Select(v => (double)v.Ticks)
                .PopulationStandardDeviation());
    }
}

And here are the tests:

[TestClass]
public class StandardDeviationTest
{
    private readonly double[] EmptySet = new double[] {};
    private readonly double[] SingleValue = new double[] { 1.0 };
    private readonly double[] SameValues = new double[] { 5.0, 5.0, 5.0 };
    private readonly double[] ScenarioValues = new double[] { 2.0, 4.0, 4.0, 4.0, 5.0, 5.0, 7.0, 9.0 };
 
    private const double ScenarioValuesSampleDeviation = 2.13809;
    private const double ScenarioValuesPopulationDeviation = 2.0;
 
    [TestMethod]
    public void SampleStandardDeviation_EmptySet_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, EmptySet.SampleStandardDeviation());
    }
 
    [TestMethod]
    public void SampleStandardDeviation_SingleValue_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, SingleValue.SampleStandardDeviation());
    }
 
    [TestMethod]
    public void SampleStandardDeviation_SetOfSameValues_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, SameValues.SampleStandardDeviation());
    }
 
    [TestMethod]
    public void SampleStandardDeviation_ScenarioValues_HaveExpectedDeviation()
    {
        Assert.AreEqual(ScenarioValuesSampleDeviation, Math.Round(ScenarioValues.SampleStandardDeviation(), 5));
    }
 
    [TestMethod]
    public void SampleStandardDeviation_TimeSpanScenarioValues_HaveExpectedDeviation()
    {
        var timeSpanValues = ScenarioValues.Select(seconds => new TimeSpan(0, 0, (int)seconds));
        var result = timeSpanValues.SampleStandardDeviation().TotalSeconds;
        Assert.AreEqual(ScenarioValuesSampleDeviation, Math.Round(result, 5));
    }
 
    [TestMethod]
    public void PopulationStandardDeviation_EmptySet_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, EmptySet.PopulationStandardDeviation());
    }
 
    [TestMethod]
    public void PopulationStandardDeviation_SingleValue_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, SingleValue.PopulationStandardDeviation());
    }
 
    [TestMethod]
    public void PopulationStandardDeviation_SetOfSameValues_HasZeroDeviation()
    {
        Assert.AreEqual(0.0, SameValues.PopulationStandardDeviation());
    }
 
    [TestMethod]
    public void PopulationStandardDeviation_ScenarioValues_HaveExpectedDeviation()
    {
        Assert.AreEqual(ScenarioValuesPopulationDeviation, Math.Round(ScenarioValues.PopulationStandardDeviation(), 5));
    }
 
    [TestMethod]
    public void PopulationStandardDeviation_TimeSpanScenarioValues_HaveExpectedDeviation()
    {
        var timeSpanValues = ScenarioValues.Select(seconds => new TimeSpan(0, 0, (int)seconds));
        var result = timeSpanValues.PopulationStandardDeviation().TotalSeconds;
        Assert.AreEqual(ScenarioValuesPopulationDeviation, Math.Round(result, 5));
    }
}
Jun 18 11

Battlefield 3: Thunder Run

by Alex Peck

Mar 2 11

Battlefield 3

by Alex Peck

I cannot wait.

Nov 22 10

Windows Phone 7 OneNote SkyDrive synchronization

by Alex Peck

This would appear to be a straightforward process, as described here. However, when I did it, I persistently received Error 8007002: synchronization failure.

My workaround was as follows:

      1. Using a PC, create a new notebook in SkyDrive. Open the new notebook and the Personal (Web) notebook in seperate tabs. Copy the contents from the old to teh new (the tedious part).
      2. Using your phone, go to office.live.com and log in. Open the new notebook in OneNote.
      3. Using your phone, set the new notebook as default and remove Personal (Web).
      4. Using a PC, delete the Personal (Web) notebook from skydrive

I later got Error 8007002 after renaming a section (which is a bug), and had to repeat the process yet again. So, don’t rename sections!

Nov 5 10

Programming Windows Phone 7

by Alex Peck

Programming Windows Phone 7 by Charles Petzold is available for free here.

Charles Petzold: Branded

Oct 19 10

Natural User Interface TechTalk

by Alex Peck


Get Microsoft Silverlight

Bill Buxton gives a great historical perspective on user interfaces and the pace of innovation.

Sep 16 10

Ken Block Gymkhana 3 Part 2

by Alex Peck

Not sure I’m a big fan of the Fiesta.

Jul 26 10

Touchable Holograms

by Alex Peck

Jul 19 10

Ballmer and Ozzie at D8

by Alex Peck

Jun 28 10

Administrative Shares in Windows 7

by Alex Peck

Perhaps this is old news for seasoned Win7 users, but today I was totally baffled when trying to copy some files via an administrative share. In Windows 7, by default, you will get an access denied message.

First disable Homegroup. Apart from anything else, the passkey it generates doesn’t look very secure to me. Perhaps it’s useful if you have no idea how to set up file sharing. If you have no idea, you probably don’t want to use administrative shares.

Second, enable File and Printer Sharing. Aside: I previously wasted literally minutes of my life when I found Vista doesn’t respond to ping when this is disabled.

  • Open Network and Sharing Center, click on Change advanced sharing settings.
  • Open your current profile (e.g Home or Work)
  • Under File and Printer sharing, ensure Turn on file and printer sharing is selected.

Third, edit the registry. This is largely for my own reference: I know for a fact that I would never be able to remember the required registry key.

  • Navigate to HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
  • Add a new DWORD key called LocalAccountTokenFilterPolicy
  • Set the new key to a value of 1

This registry key is effective immediately, no need to restart.