Creating a Math Library Using Generics in C#

Creating a Math library using Generics in C#

Here is a way to abstract out the operators that is relatively painless.

    abstract class MathProvider<T>
{
public abstract T Divide(T a, T b);
public abstract T Multiply(T a, T b);
public abstract T Add(T a, T b);
public abstract T Negate(T a);
public virtual T Subtract(T a, T b)
{
return Add(a, Negate(b));
}
}

class DoubleMathProvider : MathProvider<double>
{
public override double Divide(double a, double b)
{
return a / b;
}

public override double Multiply(double a, double b)
{
return a * b;
}

public override double Add(double a, double b)
{
return a + b;
}

public override double Negate(double a)
{
return -a;
}
}

class IntMathProvider : MathProvider<int>
{
public override int Divide(int a, int b)
{
return a / b;
}

public override int Multiply(int a, int b)
{
return a * b;
}

public override int Add(int a, int b)
{
return a + b;
}

public override int Negate(int a)
{
return -a;
}
}

class Fraction<T>
{
static MathProvider<T> _math;
// Notice this is a type constructor. It gets run the first time a
// variable of a specific type is declared for use.
// Having _math static reduces overhead.
static Fraction()
{
// This part of the code might be cleaner by once
// using reflection and finding all the implementors of
// MathProvider and assigning the instance by the one that
// matches T.
if (typeof(T) == typeof(double))
_math = new DoubleMathProvider() as MathProvider<T>;
else if (typeof(T) == typeof(int))
_math = new IntMathProvider() as MathProvider<T>;
// ... assign other options here.

if (_math == null)
throw new InvalidOperationException(
"Type " + typeof(T).ToString() + " is not supported by Fraction.");
}

// Immutable impementations are better.
public T Numerator { get; private set; }
public T Denominator { get; private set; }

public Fraction(T numerator, T denominator)
{
// We would want this to be reduced to simpilest terms.
// For that we would need GCD, abs, and remainder operations
// defined for each math provider.
Numerator = numerator;
Denominator = denominator;
}

public static Fraction<T> operator +(Fraction<T> a, Fraction<T> b)
{
return new Fraction<T>(
_math.Add(
_math.Multiply(a.Numerator, b.Denominator),
_math.Multiply(b.Numerator, a.Denominator)),
_math.Multiply(a.Denominator, b.Denominator));
}

public static Fraction<T> operator -(Fraction<T> a, Fraction<T> b)
{
return new Fraction<T>(
_math.Subtract(
_math.Multiply(a.Numerator, b.Denominator),
_math.Multiply(b.Numerator, a.Denominator)),
_math.Multiply(a.Denominator, b.Denominator));
}

public static Fraction<T> operator /(Fraction<T> a, Fraction<T> b)
{
return new Fraction<T>(
_math.Multiply(a.Numerator, b.Denominator),
_math.Multiply(a.Denominator, b.Numerator));
}

// ... other operators would follow.
}

If you fail to implement a type that you use, you will get a failure at runtime instead of at compile time (that is bad). The definition of the MathProvider<T> implementations is always going to be the same (also bad). I would suggest that you just avoid doing this in C# and use F# or some other language better suited to this level of abstraction.

Edit: Fixed definitions of add and subtract for Fraction<T>.
Another interesting and simple thing to do is implement a MathProvider that operates on an abstract syntax tree. This idea immediately points to doing things like automatic differentiation: http://conal.net/papers/beautiful-differentiation/

Any elegant way to operate with generic types?

If Eric ever reads this,

If you want something brought to my attention, try the contact link on my blog. Or put my full name in the text of the question so that me searching for myself will find me.

does this feature (constraining generic types by defined operators) ever come up in hypothetical future versions of C# design meetings and has it ever been close to making it into the language?

Indeed, this is a frequently requested feature. We've been getting requests for this sort of thing since C# 1.0.

The feature would requires support from the CLR team, not just the language -- it is the sort of feature that we would want to integrate into all our languages, which increases the cost.

The CLR team has expressed interest in features like this, but they also have a lot of competing features that they could be doing, and limited time and effort to implement those features.

There are numerous ways such a feature could be implemented. For example, we could add the ability to specify static methods in interfaces:

interface IAddable<T>
{
static T operator+(T x, T y);
}

and then

static T Sum<T>(IEnumerable<T> seq) where T : IAddable<T>
{
T sum = default(T);
foreach(T item in seq) sum = sum + item;
return sum;
}

The idea would be that the interface means "a type that implements this interface must have the given static methods". We'd then make int automatically implement IAddable<int>, and so on.

How do do so efficiently in a world with runtime-generated generic code is an open question.

I hasten to add that this is just a sketch of an idea. There are many ways to implement this sort of feature. The "statics in interfaces" idea is one that has broader usage than just mathematics, and that's attractive to us. If we're going to go to the huge expense of this sort of feature, it would be nice to have a really general, powerful feature rather than one narrowly focussed on math.

On the other hand, the perfect is the enemy of the good; it might be better to just concentrate on the math problem and not go for a more expensive general solution.

It's an ongoing debate. It is definitely on everyone's radar screen, but I would not expect it any time soon. The language designers are all heads-down working on going through the feedback from the async CTP.

As always, Eric's musings about hypothetical future language features of hypothetical unannounced future products are for entertainment purposes only.

Math.Abs(T value) generics c#

Six options:

  • Use reflection based on the execution-time type of T
  • Use an overload for each type you care about
  • Use if/else for every type you care about
  • Create a Dictionary<Type, Func<object, object>> containing a delegate for every type you care about
  • Use dynamic in .NET 4:

    public T Foo<T>(T value)
    {
    dynamic d = value;
    return Math.Abs(d);
    }
  • Use something like Marc Gravell's generic operators part of MiscUtil

I'd probably go for the overload option if possible. It will constrain you appropriately at compile-time, and avoid any potentially time-consuming boxing/reflection.

Should I use generics for 3D Points and Vectors when developing a library?

Without having more context on your exact problem, I would say no you should not use generics in this case. A C# generic method can only reference properties or methods known to exist on T at compile time. For example, this method works:

public string GetString<T>(T obj) { return obj.ToString(); }

The reason that compiles fine is because ToString() is defined on System.Object and everything inherits that.

For a point-like or vector-like type, you might want something like this:

public int GetMagnitude<T>(T vector) {
return Math.Sqrt(vector.X + vector.Y);
}

However, not all types have an X and Y, so generic constraints are required. Here are the official docs: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/constraints-on-type-parameters

What is relevant for your case, is that you need to constrain to types that inherit a base class or implement an interface. Something like:

public int GetMagnitude<T>(T vector) where T : IVector {
return Math.Sqrt(vector.X + vector.Y);
}

The problem here is that any possible library you want to use this with would have to make their vector class implement this interface, and there is no commonly used interface for this that would be a safe choice.


Possibly of interest is the proposed language feature "Shapes". https://github.com/dotnet/csharplang/issues/164

This would allow more of a "duck-typing" approach to generics.

This has been in the backlog for a while. It looked like a possible candidate for C#8 early in that development cycle, now it's a possibility for C#9, so don't get your hopes up.

Implementing arithmetic in generics?

Unfortunately you cannot use arithmetic operations on generic types

T Add(T a, T b)
{
return a + b; // compiler error here
}

will not work in c#!

But you can create your own numeric types and overload the operators (arithmetic, equality and implicit, explicit). This lets you work with them in a quite natural way. However you cannot create an inheritance hierarchy with generics. You will have to use a non generic base class or interface.

I just did it with a vector type. A shortened version here:

public class Vector
{
private const double Eps = 1e-7;

public Vector(double x, double y)
{
_x = x;
_y = y;
}

private double _x;
public double X
{
get { return _x; }
}

private double _y;
public double Y
{
get { return _y; }
}

public static Vector operator +(Vector a, Vector b)
{
return new Vector(a._x + b._x, a._y + b._y);
}

public static Vector operator *(double d, Vector v)
{
return new Vector(d * v._x, d * v._y);
}

public static bool operator ==(Vector a, Vector b)
{
if (ReferenceEquals(a, null)) {
return ReferenceEquals(b, null);
}
if (ReferenceEquals(b, null)) {
return false;
}
return Math.Abs(a._x - b._x) < Eps && Math.Abs(a._y - b._y) < Eps;
}

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

public static implicit operator Vector(double[] point)
{
return new Vector(point[0], point[1]);
}

public static implicit operator Vector(PointF point)
{
return new Vector(point.X, point.Y);
}

public override int GetHashCode()
{
return _x.GetHashCode() ^ _y.GetHashCode();
}

public override bool Equals(object obj)
{
var other = obj as Vector;
return other != null && Math.Abs(other._x - _x) < Eps && Math.Abs(other._y - _y) < Eps;
}

public override string ToString()
{
return String.Format("Vector({0:0.0000}, {1:0.0000})", _x, _y);
}
}

How to use generics to develop code that works for doubles and decimals

You can't use operators in generics without specifying a base class constraint on the T.

You might do something like this: Creating a Math library using Generics in C# but personally, unless you really have lots of different formulae then I don't see much point.

There's also the possibility of dynamically compiling expression trees for T, rewriting the types between double/decimal from a 'model' tree generated by the C# compiler (keeping the arithmetic precedence etc)... if you're really interested in that I can post the code for such a solution (I'll need an hour or so though!). Runtime performance will be slower.

C#: generic math functions (Min, Max etc.)

If you only want to create comparison functions then you could use the default comparer for the type T. For example:

public static T Max<T>(T x, T y)
{
return (Comparer<T>.Default.Compare(x, y) > 0) ? x : y;
}

If T implements IComparable<T> then that comparer will be used; if T doesn't implement IComparable<T> but does implement IComparable then that comparer will be used; if T doesn't implement either IComparable<T> or IComparable then a runtime exception will be thrown.

If you want/need to do more than just compare the items then you could have a look at the generic operators implementation in MiscUtil and the related article.

Less generic generics? A possible solution for arithmetic in C# generics

I think you are looking for the functionality of a functional programming language in OOP. If that is the case, then use FP.

For example, in Scala, you can replace the operators, so now it can add or multiply your matrix.

This is the case in various languages, but not all OOP languages.

Why should generics be able to do addition when it isn't obvious how to add or multiply? For example, if I have a class of logarithms, then to multiply is just adding the numbers, but, how could a compiler know that?

In C# you can do operator overloading, which should solve the problem you are complaining about:
http://msdn.microsoft.com/en-us/library/aa288467%28VS.71%29.aspx

The C# team came to decisions on how to do generics, and it shouldn't handle math as my example above would show, but they did allow for you to help the compiler know how to do the math operations, so blaming them for not asking them for your opinion first is very risky, as the decision has been made, generics are in as they are. It won't be changed now, I believe.



Related Topics



Leave a reply



Submit