Click here to Skip to main content
Click here to Skip to main content

Using generics for calculations

By , 11 Oct 2004
 
Prize winner in Competition "C# Sep 2004"

Introduction

The current implementation of .NET generics is used mainly to make type-safe collections faster and more easy to use. Doing calculations on generic types is not as straightforward.

The problem

An example for doing calculations on generic types would be a generic method to calculate the sum of all elements in a List<T>. Of course, summing up all elements of a list only makes sense if T is a type such as int, double, decimal that defines an addition operation.

Somebody coming from a C++ background might implement such a method like this:

public class Lists {
    ...
    public static T Sum(List<T> list) 
    {
        T sum=0;
        for(int i=0;i<list.Count;i++)
            sum+=list[i];
        return sum;
    }
    ...
}

This is not possible in C# because unconstrained type parameters are assumed to be of type System.Object, which does not define a + operation.

To constrain type parameters in C#/.NET, you specify interfaces that the type has to implement. The problem is that interfaces may not contain any static methods, and operator methods are static methods.

So with the current constraint system, it is not possible to define operator constraints.

A clean way to enable numerical computations would be to let the basic data types like int, float, double, decimal etc. implement an interface for arithmetic operations. Then this interface could be used to constrain the type parameters. This would work similar to the IComparable<T> interface that all basic data types implement.

I tried to convince the people at Microsoft to implement such an interface, but apparently they won't be able to do it in time for Whidbey.

We are on our own

Many people have been thinking about this problem, among them Eric Gunnerson and even Anders Hejlsberg.

The solution proposed by Anders Hejlsberg was to have an abstract class Calculator<T> that has to be specialized for each primitive type. The generic type would then use an instance of the appropriate calculator to do the calculations.

Here is the code (copied from Eric Gunnerson's Blog):

First define the abstract base class:

public abstract class Calculator<T>
{
    public abstract T Add(T a, T b);
}

Then specialize for the types you want to perform calculations on:

namespace Int32
{
    public class Calculator: Calculator<int>
    {
        public override int Add(int a, int b)
        {
            return a + b;
        }
    } 
}

Then use an appropriate Calculator<T> to do the calculations. Here is an example that calculates the sum of all elements in a List<T>.

class AlgorithmLibrary<T> where T: new() 
{
    Calculator<T> calculator;

    public AlgorithmLibrary(Calculator<T> calculator)
    {
         this.calculator = calculator;
    } 

    public T Sum(List<T> items)
    {
        T sum = new T(); 

        for (int i = 0; i < items.Count; i++)
        {
            sum = calculator.Add(sum, items[i]);
        } 

        return sum;
    }
}

You would use it like this:

AlgorithmLibrary library = new AlgorithmLibrary<int>(new Int32.Calculator());

There are many other creative solutions, but all of them have the drawback that they involve some kind of dynamic method invocation (virtual methods, interfaces or delegates). So while they make it possible to perform calculations with generic type parameters, the performance is unacceptably low for numerical applications.

The Solution

The first person to come up with a solution that does not involve any virtual method invocation was Jeroen Frijters. The solution uses the fact that constraining type parameters using interfaces is not the same as casting to interfaces. Calling a method using an interface has the overhead of dynamic method dispatch, but calling a method on a type parameter that is constrained by an interface has no such overhead.

Here is an example. It is a generic method that sorts two numbers. The type T has to implement IComparable<T> so that we can be sure that it has the CompareTo method. But nevertheless, calling the CompareTo method does not have the overhead normally associated with interfaces.

public class Sorter
{
    private static void Swap<T>(ref T a, ref T b)
    {
        T t=a;a=b;b=t;
    }
    public static void Sort<T>(ref T a,ref T b)
        where T:IComparable<T>
    {
        if(a.CompareTo(b)>0)
            Swap(ref a,ref b);
    }
}

The approach suggested by Jeroen Frijters uses a second type parameter. To avoid unnecessary object creation and virtual method dispatch, it is best to use a value type for the type containing the operations. Here is a small example for this approach:

interface ICalculator<T> 

{ 
    T Sum(T a,T b); 

} 

struct IntCalculator : ICalculator<int> 

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

} 

// struct FloatAdder ... 

// struct DoubleAdder ... 

class Lists<T,C>
    where T:new() 
    where C:ICalculator<T>,new();{
    //since C is a struct with zero size, we can create an instance
    //of C whenever we need one without any overhead.
    private static C calculator=new C();
    public static T Sum(List<T> list) 
    { 
        T sum=new T();
        for(int i=0;i<list.Count;i++)
            sum=calculator.Add(sum,list[i]); 
        return sum; 
    } 

}

The use of this class is a bit awkward because of the second type parameter. But you could use an alias. Here is how you would use the Lists<T,C> type:

using IntLists=Lists<int,IntCalculator>;
//...
List<int> list=new List<int>();
list.Add(1);
list.Add(2);
list.Add(3);
Console.WriteLine("The sum of all elements is {0}",
IntLists.Sum(list));

Performance

Since we made sure that our code does not contain any virtual method calls or unnecessary object creation, the generic code should be exactly as fast as non-generic code. To test this, I wrote a small benchmark. The result is encouraging. Even the current very limited JIT compiler manages to inline the Sum method, so the generic version is indeed exactly as fast as the non-generic version on my machine.

Please make sure that you run the benchmark in release mode, since in debug mode many very important optimizations such as method inlining are disabled.

Using operators with type parameters

We now can do calculations on generic types with acceptable performance. But we still can not use operators with type parameters. In the above example, we had to write sum=calculator.Add(sum,list[i]) instead of simply writing sum+=list[i].

This might not be a big deal if you want to perform a simple addition. But if you have large, complex methods that excessively use operators, it would be a tedious and error-prone process to convert them to use method calls instead.

Fortunately, it is possible to create a wrapper struct that defines operators. By using implicit conversions to and from the wrapped type, we can use this wrapper struct almost transparently.

This is how a wrapper struct for the above ICalculator interface might look like:

public struct Number<T,C>
    where C:ICalculator<T>,new()
{
    private T value;
    private static C calculator=new C();
    private Number(T value) {
        this.value=value;
    }
    public static implicit operator Number<T,C>(T a)
    {
        return new Number<T,C>(a);
    }
    public static implicit operator T(Number<T,C> a)
    {
        return a.value;
    }
    public static Number<T,C> operator + (Number<T,C> a, Number<T,C> b)
    {
        return calculator.Add(a.value,b.value);
    }
    ...other operators...
}

Now, instead of using T in your generic class, you would just use the wrapper struct instead. Here is how the Sum example would look like using the wrapper struct:

class Lists<T,C>
    where T:new()
    where C:ICalculator<T>,new()
{
    public static T Sum(List<T> list)
    {
        Number<T,C> sum=new T();
        for(int i=0;i<list.Count;i++)
            sum+=list[i];
        return sum;
    }
}

You might expect that this code runs exactly as fast as the non-operator version. But unfortunately, this is not the case. The current .NET JIT compiler has some very serious limitations. Basically, it does not do any inlining if a method has an explicit struct parameter (Yes, I was shocked too).

Since the operator methods in the wrapper struct have struct parameters, they will not be inlined, so the performance will suffer. But I am sure that Microsoft will fix this important performance issue soon.

Here is a suggestion about this topic that you can vote for. This is the only thing that is missing for lightning-fast and easy to use numerics in C#.

Conclusion

Even though the constraint syntax of .NET generics system is very limited, it is possible to work around those limits by using a second type parameter. This approach is a bit more work for the writer of the generic class library, but it is quite transparent for the user of the class library and it yields performance that is identical to a non-generic version. Just like with C++ templates, the runtime cost of the abstraction is zero.

There are some limitations, but these should go away very soon as Microsoft and the competing vendors improve the JIT compiler performance. So, it is possible to write numeric libraries that are as fast or even faster than compile-time template libraries such as the C++ STL.

About the code

The included project consists of interfaces, implementations and wrappers for all primitive types with a few nice additions. The list benchmark calculates the standard deviation of a large list both with generic and with non-generic methods. Another benchmark compares the performance of the non-generic System.Drawing.Point and System.Drawing.PointF structs with a generic Point<T> version.

The code is under the BSD license, so feel free to use it for your own projects.

References

  • Anders Hejlsberg proposed using an abstract base class.
  • A solution using dynamic method generation.
  • Jeroen Frijters proposed using value types for the calculator.
  • This was my first posting about the topic. As you might notice, I was quite angry...
  • Here is where I will publish newer versions of the code.
  • Two articles by me on osnews about the topic.
  • Please vote for this suggestion. It is more important than the presidential elections :-)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Rüdiger Klaehn
Web Developer
Germany Germany
Member
Rüdiger Klaehn works as freelance developer in the space industry. He is very interested in functional programming languages and hopes that .NET will lead to a more widespread adoption in the industry.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionOverloading operators is a much more userfriendly waymemberRed Baron18 Dec '12 - 0:04 
public static MyClass<T> operator +(MyClass<T> a, MyClass<T> b)
        {
            switch (Type.GetTypeCode(typeof(T)))
            {
                case TypeCode.Double:
                    //Define addition-routine for Double
                    break;
                case TypeCode.Int32:
                    //Define addition-routine for Int32
                    break;
            }
            return null;
        }
 
In the //Define ... block you have to describe how you can add your objects containing generic type. If you have a class MyMatrix for example, in the various cases you can describe how two matrices can be added to each other (if your matrix contains a two dimensional array, you just have to add the elements of the array in a specific way (sum of matrix -> wikipedia)). The same applies for *, / etc.
 
After that you can simply use it as we are used to with normal numbers!
 
Example:Let's say we have defined a Point-class that supports generict types for its 2 attributes - x and y coordinates. We have also overloaded the '+'-operator to support addition of points.
 
Point<double> ob1 = new Point<double>(12.0, 10.0); //param1 = x coordinate, param2 = y coordinate
Point<double> ob2 = new Point<double>(13.0, 40.0);
Point<double> obSum = ob1 + ob2;
//Point obSum now has x = 25.0 and y = 50.0

GeneralMy vote of 5memberFrederico Barbosa13 Nov '12 - 0:49 
It's amazing how the same problems surface again and again and again... Thanks for this article. I only regret not having stumbled on it sooner.
QuestionAwesome article, 5*memberandyb197929 Apr '12 - 23:51 
Thanks for the fantastic comparison article. Of particular interest was the Generic Sum technique.
GeneralUsing C# 4.0, there's a much nicer way...memberPater5 May '11 - 3:40 
With the new possibilities of .NET 4.0, there's a much nicer way of doing it. The key to the magic is the new "dynamic" type.
 
public struct Vector<T>
{
    private dynamic m_x;
    private dynamic m_y;
    public Vector(T x, T y) 
    {
        m_x=x;
        m_y=y;
    }
    public static Vector<T> operator + (Vector<T> a, Vector<T> b)
    {
        return new Vector<T>(a.x+b.x,a.y+b.y);
    }
    //...other operators...
}
 
This omits all the fancy stuff with helper classes or interfaces and jsut works as you would expect it when you where used to C++-templates. The drawback is that everything involving a dynamic type is compiled at runtime, so this comes with a performance penalty. The other problem is that any type errors will only show up at runtime. So, for the above examle, you're fine when adding any types that implement a + operator, including, but not limited to int, double, float, string. However, if you create a Vector<Form> type, adding them will cause a runtime exception.
GeneralRe: Using C# 4.0, there's a much nicer way...membericetea9427 Apr '12 - 2:56 
The dynamic approach takes approximately ten times more time than the generic approach presented in the article, so I would strongly discourage from using dynamic types in any numerical calculation. Besides of the compilation at runtime, the functions are called by a delegate, which has about the cost of a virtual method call.
GeneralRe: Using C# 4.0, there's a much nicer way...memberPater27 Apr '12 - 3:53 
I know that it's more expensive, but it is much nicer to use. You don't have to create any Number classes or something of the kind. So whoever uses your, say Vector can use it directly with int or double, as one was used to when working with C++.
GeneralMy vote of 5memberSteven Jeuris8 Feb '11 - 8:38 
Perfect, cleanest solution I found on the subject.
GeneralMy vote of 5memberAshley Davis1 Feb '11 - 9:25 
Nice solution.
GeneralWhy doesn't IMath implement IComparer. [modified]memberSteven Jeuris4 Jan '11 - 13:44 
Hey Rüdiger,
 
First of all, thanks for this implementation. I came across this problem several times, and I find this solution quite useful!
 
While doing an implementation, I had to be able to compare one value with another. I noticed IMath didn't implement IComparer. However, all interfaces which implement IMath do implement IComparer.
 
I now simply let IMath implement IComparer directly so I can access those functions. Is there any reason not to do this?
 
UPDATE:
Same holds for ILimitProvider<T> and IConversionProvider<T>.
 
Greetings!
Steven Jeuris - Whathecode
modified on Thursday, January 6, 2011 9:39 AM

GeneralGeneric Numerics classmemberSteve Hansen11 Aug '09 - 1:10 
I found a way to create a single generic class that will handle all numeric (well structs)
 
        static void Test()
        {
            int intResult = Calculator<int>.Add(1, 5);
            double doubleResult = Calculator<double>.Add(1.5, 4.5);
            DateTime timeResult = Calculator<DateTime>.Add(DateTime.Today, DateTime.Today);
        }

GeneralRe: Generic Numerics classmemberSteve Hansen26 Aug '09 - 22:02 
This code will handle most cases, just use ilasm to build a dll
 
.class public abstract auto ansi sealed beforefieldinit Numerics.Calculator`1<valuetype .ctor ([mscorlib]System.ValueType) T>
       extends [mscorlib]System.Object
{
  .method public hidebysig static !T  Add(!T arg1,
                                          !T arg2) cil managed
  {
    .maxstack  2
    .locals init (!T V_0)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldarg.1
    IL_0003:  add
    IL_0004:  stloc.0
    IL_0005:  br.s       IL_0007
 
    IL_0007:  ldloc.0
    IL_0008:  ret
  }
 
  .method public hidebysig static !T  Subtract(!T arg1,
                                               !T arg2) cil managed
  {
    // Code size       9 (0x9)
    .maxstack  2
    .locals init (!T V_0)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldarg.1
    IL_0003:  sub
    IL_0004:  stloc.0
    IL_0005:  br.s       IL_0007
 
    IL_0007:  ldloc.0
    IL_0008:  ret
  }
 
}

GeneralMethods with value type parameters are now inlined in .NET 3.5 SP1memberBen Cooley24 Feb '09 - 7:24 
Accordin to this article http://blogs.msdn.com/clrcodegeneration/archive/2007/11/02/how-are-value-types-implemented-in-the-32-bit-clr-what-has-been-done-to-improve-their-performance.aspx[^] this limitation has been removed from the latest version of the x86 CLR. However several people have reported that this limitation still exists in the x64 CLR.
 
I wasn't able to discover whether inlining of methods with structs was supported by the Mono CLR.
GeneralHellomemberTheraot22 Feb '09 - 20:38 
Hey Rüdiger Klaehn, looks like you have been tracking this from the very premiere of generics on .NET.
 
Ok, I came looking for you Rüdiger, cuz I wanted to show you this:
 
http://www.codeproject.com/KB/dotnet/HardcoreDotNET.aspx[^]
 
Please your opinion.
 
Alfono J. Ramos (Theraot)
QuestionWhat would be the performance of using type parameters in interfaces as method selectors?membersupercat916 Jan '09 - 14:09 
I originally wrote most of the following post for a slightly different subject, but it seems like it may be apropos here. The basic goal seems to be to allow something like a generic collection to invoke an arbitrary number of different methods on its members. Using generics, that can be done. First I code something like:
Class DoItMagic
    Interface iAct(Of T)
        Sub Act(ByVal param As T)
    End Interface
 
    Public Shared Sub exec(Of T)(ByVal target As iAct(Of T), ByVal param As T)
        target.Act(param)
    End Sub
End Class
 
Now if I want to allow a class to perform any of several methods, I simply define a class holding the parameters appropriate to each method, and can then use the exec function to call it. For example, here's a class that supports two methods (using argument types param1 and param2):
Class DoItTarget
    Implements DoItMagic.iAct(Of param1), DoItMagic.iAct(Of param2)
 
    Class param1
    End Class
 
    Class param2
    End Class
 
    Public Sub Act_param1(ByVal param As param1) _
            Implements DoItMagic.iAct(Of param1).Act
        ..
    End Sub
 
    Public Sub Act_param2(ByVal param As param2) _
            Implements DoItMagic.iAct(Of param2).Act
        ..
    End Sub
End Class
 
Now it's possible to write a generic routine that will, e.g., take a generic list of holding any object that implements a particular version of iAct, and invoke the iAct handler upon it.
 
Class DoItTest
    Public Shared Sub hitEverything(Of T, U As DoItMagic.iAct(Of T)) _
        (ByVal theList As List(Of U), ByVal theParam As T)
        For Each thing As U In theList
            DoItMagic.exec(Of T)(thing, theParam)
        Next
    End Sub
 
    Dim firstParam As DoItTarget.param1
    Dim secondParam As DoItTarget.param2
 
    Dim L As List(Of DoItTarget)
 
    Sub go()
        hitEverything(Of DoItTarget.param1, DoItTarget)(L, firstParam)
        hitEverything(Of DoItTarget.param2, DoItTarget)(L, secondParam)
    End Sub
End Class
 
This approach may end up generating lots of redundant classes that hold nothing but fields (no methods), as well as lots of iAct(of T) generic classes. On the other hand, it allows (or seems to allow) one to invoke any of a number of methods upon a class quickly and easily. Everything seems to be type-checked at compile time, but I have no idea what has to go on behind the scenes to make everything actually work.
 
I don't want to write an article promoting this method if the code it generates behind the scenes ends up being lousy (or works beautifully when there are fewer than 30 classes, and dogs horribly when there are 100). What do you think of it as an approach?
GeneralMicrosoft now claims the IArithmetic inteface inventionmembermarcuzzi29 Dec '08 - 12:35 
After years waiting for IArithmetic, Microsoft now claims a patent on it.
 
http://www.freshpatents.com/Generic-interface-for-numeric-types-dt20080828ptan20080209394.php
 
This annoys me even more! Mad | :mad:
GeneralSolving this with Linq Expression trees.memberRoger Alsing26 Feb '08 - 21:29 
I've made a little sample on how this can be solved with Linq Expression Trees:
http://rogeralsing.com/2008/02/27/linq-expressions-calculating-with-generics/[^]
 
With this approach you no longer need any calculator providers.
 

Generalcode snippets in this article are stolel from richters bookmemberf_numb3r30 Nov '07 - 2:57 
most code snippets in this article are stolel from J.Richter's book,
 
for ex. the Swap method ..
GeneralRe: code snippets in this article are stolel from richters bookmemberRüdiger Klaehn15 Feb '08 - 3:40 
Nothing in this article is stolen from J.Richter's book. This article was released in 2004, while the book (CLR via C#, Second Edition) is much younger.
 
When I took ideas from other people (most notably Jeroen Frijters), I gave them credit.
 
So an apology would be in order
QuestionTemplate?memberalexandre7g17 Apr '07 - 1:55 
It's a very good article with many solutions...thks.
However I things there's a mistake between Sum and Add in the code of solution:IntCalculator must implements ICalculator with the same name of method.
 
I use it in C# but i'm interrested in using my native C++ template,is it possible with generics?Which solution have I to choose?
GeneralVBNET versionmemberfscarpa589 Mar '07 - 4:41 
Thank you very much for this technique.
I coded it in VB and it works very well.
 
I implemented it for matrix operations and it perform exactly as fast as working with primitive types directly, with double, decimal and integer while
with single it is about 30% slower (time is 150%).
Obviously I am speaking about Release run. in debug mode execution time increases up to 3 times with respect to directly using primitive types.
 
Federico


GeneralRe: VBNET versionmemberRoss Presser20 Jun '07 - 7:45 
Could you provide a link to your matrix version?

GeneralMin and Max are wrongmemberomanuke14 Jan '07 - 17:27 
Implementations for Min And Max in Calculator.cs are wrong.
All of them should be reversed.

GeneralRe: Min and Max are wrongmemberSteven Jeuris6 Jan '11 - 14:26 
I just noticed the same thing, thanks.
GeneralMy solution [modified]memberDuncanWoods6 Jul '06 - 0:08 
I don't like having to pass a calculator to any numerical generic class. Here is my work-around that is no doubt poorer performance but acceptable in my context:
 
I can multiply by just:
 
   T a = GenericCalculations<T>.Multiply(b, c);
 

Using a class implented like:
 

      public abstract class GenericCalculations<T>
      {
            // Keeps compiler happy
            public static T Multiply(object i, object j)
            {
                  return (T)i;
            }
 
            // Actual implementations
            public static T Multiply(short i, short j)
            {
                  object result = i * j;
                  return (T)result;
            }
            public static T Multiply(ushort i, ushort j)
            {
                  object result = i * j;
                  return (T)result;
            }
 
... etc
 
-- modified at 6:08 Thursday 6th July, 2006
GeneralUpdatememberfdssfsdfsdfsdfsd20 Feb '06 - 19:03 
It's been about two years now since this article was published - are there any news (I doubt) ?
 
It's clever; but still messy compared to the traditional c++
 
This is another classic example of where standards overwhelm the underlying functionality - this is propably the biggest flaw in the entire .net platform I've come to learn of; I was running into the same problem and stumbled upon your article - thanks - is cleared up a whole lot of questions.
 
When it comes to realtime or intense 3d mathematical development that you find in all good 3d games; this stuff is mostly the core of the engines and is relied upon heavily for performance and rendering accuracy.
 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 11 Oct 2004
Article Copyright 2004 by Rüdiger Klaehn
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid