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:

Average a = 5;
a += 6;

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

Average a = 1;
a += 2;
Average b = 3;
b += 4;
var c = a + b;

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)]
        private readonly decimal _Count;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private readonly decimal _Value;

        #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
    }
}