I would like to have the following class for multiple types (eg float, double, decimal):
internal class Progressing_Average
{
public Progressing_Average()
{
_Count = 0;
Value = 0;
}
public double Value { get; private set; }
private int _Count { get; set; }
public void AddValue(double input)
{
if (_Count == int.MaxValue)
{
throw new IndexOutOfRangeException("max amount has been reached! use preciseaverage or moving avg instead!");
}
_Count++;
Value += (input - Value) / _Count;
}
}
I tried with internal class Progressing_Average<T> but the issue is that i cant perform all nessesary operations on T
Operator '-' cannot be applied to operands of type 'T' and 'T'
Is there a way to do this, does it come with performance implications or should I rather use something in the lines of Processing_Average_Double
having one class for each type makes the code quite duplicate and harder to maintain i believe
>Solution :
Here is the example code you asked for
class Program
{
static void Main(string[] args)
{
var avg_float = new Progressing_Average<float>();
avg_float.AddValue(1f);
avg_float.AddValue(2f);
avg_float.AddValue(3f);
Console.WriteLine($"ave={avg_float.Value:f4}");
var avg_dec = new Progressing_Average<decimal>();
avg_dec.AddValue(1m);
avg_dec.AddValue(2m);
avg_dec.AddValue(3m);
Console.WriteLine($"ave={avg_dec.Value:c}");
}
}
with sample output
ave=2.0000
ave=$2.00
Generic Math
Ever since NET 3.5, you can do generic math using Expressions and Lambda functions. There is a bit of setup that is needed, but the example below is fairly straight forward.
Some notes:
-
Define generic parameter
Tand restrict it to numeric types. Newer NET implementations have better ways of doing this but for compatibility, with .NET Framework I use the followingwhereconstraint inT -
Define static methods (actually static anonymous functions) for the required math operations. Some basic ones are
+,-,*,/and the conversion frominttoTfor mixing_Count.These methods are built using a static constructor for the type and are called once for each different
Tused. -
Replace the math operators with the equivalent functions. Like
a+bbecomesAdd(a,b).
Class Definition
public class Progressing_Average<T> where T: struct,
IComparable,
IComparable<T>,
IConvertible,
IEquatable<T>,
IFormattable
{
static Progressing_Average()
{
var a = Expression.Parameter(typeof(T));
var b = Expression.Parameter(typeof(T));
var n = Expression.Parameter(typeof(int));
Add = Expression.Lambda<Func<T, T, T>>(Expression.Add(a, b), a, b).Compile();
Sub = Expression.Lambda<Func<T, T, T>>(Expression.Subtract(a, b), a, b).Compile();
Mul = Expression.Lambda<Func<T, T, T>>(Expression.Multiply(a, b), a, b).Compile();
Div = Expression.Lambda<Func<T, T, T>>(Expression.Divide(a, b), a, b).Compile();
FromInt = Expression.Lambda<Func<int, T>>(Expression.Convert(n, typeof(T)), n).Compile();
}
static Func<T, T, T> Add { get; }
static Func<T, T, T> Sub { get; }
static Func<T, T, T> Mul { get; }
static Func<T, T, T> Div { get; }
static Func<int, T> FromInt { get; }
public Progressing_Average()
{
_Count = 0;
Value = FromInt(0);
}
public T Value { get; private set; }
private int _Count { get; set; }
public void AddValue(T input)
{
if (_Count == int.MaxValue)
{
throw new IndexOutOfRangeException("max amount has been reached! use preciseaverage or moving avg instead!");
}
_Count++;
Value = Add(Value, Div(Sub(input, Value), FromInt(_Count)));
}
}