I am obsessed with code performance, and calculating the performance of long-running algorithms entails – a lot of the times – calculating averages.

To make calculating averages easier (that’s the kind of lazy person I am) I’ve written a few lines of code. Specifically, I’ve written an immutable data-structure in C# that can be used to keep track of an average, without having to calculate the average from the beginning every time a new value is added. The math is ridiculously easy, so I went get into that. The reason I like this data-structure is that it’s very easy to use. Here’s what you have to do to calculate a new average:

If you check the property a.Value, or cast “a” to a decimal, double, or float, you’ll find that it is now equal to 5.5!

Also, averages can be added. Running the following code will result to “c” being equal to 2.5. Which is right, as

So here’s the C# struct. Do with it as you like.

``````namespace M1
{
using System.Collections.Generic;
using System.Diagnostics;

[DebuggerDisplay("\\{ Count = {Count}, Value = {Value} \\}")]
[DebuggerStepThrough]
public struct Average
{
#region Fields

[DebuggerBrowsable(DebuggerBrowsableState.Never)]

[DebuggerBrowsable(DebuggerBrowsableState.Never)]

#endregion Fields

#region Properties

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public static Average Empty { get { return new Average(); } }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public decimal Count { get { return _Count; } }

[DebuggerBrowsable(DebuggerBrowsableState.Never)]
public decimal Value { get { return _Value; } }

#endregion Properties

#region Constructors

private Average(decimal count, decimal value)
{
_Count = count;
_Value = value;
}

private Average(Average average)
: this(average.Count, average.Value)
{
}

#endregion Constructors

#region Methods

public static explicit operator double(Average average)
{
return (double)average.Value;
}

public static explicit operator float(Average average)
{
return (float)average.Value;
}

public static implicit operator Average(decimal value)
{
return new Average(1, value);
}

public static implicit operator decimal(Average average)
{
return average.Value;
}

public static bool operator !=(Average a, Average b)
{
return (!(a == b));
}

public static Average operator +(Average a, Average b)
{
if ((a == Average.Empty) && (b == Average.Empty))
return Average.Empty;

var newCount = a.Count + b.Count;
var newValue = (a.Count * a.Value + b.Count * b.Value) / newCount;
return new Average(newCount, newValue);
}

public static bool operator ==(Average a, Average b)
{
return a.Count == b.Count && a.Value == b.Value;
}

public override bool Equals(object obj)
{
if (obj == null)
return false;
if (obj.GetType() != typeof(Average))
return false;
var other = (Average)obj;
return this == other;
}

public override int GetHashCode()
{
var comparer = EqualityComparer<decimal>.Default;
var h1 = comparer.GetHashCode(Count);
var h2 = comparer.GetHashCode(Value);
return (((h1 << 5) + h1) ^ h2);
}

#endregion Methods
}
}
``````