Sign in to follow this  

[.net] Generic numeric class [C# 2.0]

This topic is 4737 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello! Is it possible to make a generic Vector class? a.) Generic static methods are not possible b.) -> no operator overloading c.) No generic properties / indexer -> use generic methods d.) ... Could I make the Vector as a Template with C++/CLI ? Thank you guys! :)

Share this post


Link to post
Share on other sites
It is possible to make a generic Vector Class with out operator overloading, I am not quiet sure what you mean by generic property and Indexer. Why try to re-invent the Vector class again... is it for a learning purpos... to understand vector class??

I am sure there are some other vector class out there, because I have used apvector class in one of my project for my college class.

Good luck with your programming. =)

Share this post


Link to post
Share on other sites
My "old" math- .dll ( C# 2003 ) has a 1.8k lines Vector3 class. The class itself was meant for us in 3D applications using OGL. So I decided to use floats. Now with C# 2.0 my hope raised that I could make a more generic Vector3 class.

I just tried out the VS 2005 C# Beta and found out about the disadvantages of generics.

1.) Most important: Generic static functions are not aviable.


public static Vector3<T> Add( Vector3<T> left, Vector3<T> right )
{
return new Vector3<T>( left.x + right.x, left.y + right.y );
}



2.) No operator overloads! I love operator overloading! v3 = v1 * s; Is clearer than with methods.

3.) Properties:

public Bla<float>
{
get{} set{}
}

Doesn't compile...





Soo... I have to make non generic versions of my Vector classes. Well that's not that hard. Eg:



using T = System.Float;

public struct Vector3
{
T x; T y; T z;
}


// ...................

using T = System.Decimal;

public struct Vector3m
{
T x; T y; T z;
}





Share this post


Link to post
Share on other sites
C# generics does support static methods and operators. Look at this article <http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnvs05/html/csharp_generics.asp> . Here is the example they give on a static method:


public class MyClass<T>
{
public static T SomeMethod<X>(T t,X x)
{..}
}
int number = MyClass<int>.SomeMethod<string>(3,"AAA");


Here is the example for an operator:


public class LinkedList<K,T>
{
public static LinkedList<K,T> operator+(LinkedList<K,T> lhs,
LinkedList<K,T> rhs)
{
return concatenate(lhs,rhs);
}
static LinkedList<K,T> concatenate(LinkedList<K,T> list1,
LinkedList<K,T> list2)
{
LinkedList<K,T> newList = new LinkedList<K,T>();
Node<K,T> current;
current = list1.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
current = list2.m_Head;
while(current != null)
{
newList.AddHead(current.Key,current.Item);
current = current.NextNode;
}
return newList;
}
//Rest of LinkedList
}

Share this post


Link to post
Share on other sites
Hmm, well. That's a list not a math- vector. A list has to use less numeric operations. =3

*thinks*

Thank you! :)








I get an error when I compile any code in C# 2005!


Warning 1 Invalid search path 'C:\Programme\Microsoft Visual Studio .NET\FrameworkSDK\Lib\' specified in 'LIB environment variable' -- 'The system couldn't find the path. '




Where can I change the 'LIB environment variable' ?


That result's into strange other errors. It can't find System.Float, ..
float (the keyword) works fine! :3


Hmm, help please :D

Share this post


Link to post
Share on other sites
To change your LIB environment variable, right-click your "My Computer" icon and select "properties". Then click the "Advanced" tab, and click on the "Environment Variables" button. There you will see a list of environment variables and they're values. You can modify them there. You may have to restart Visual Studio for the change to take effect.

Share this post


Link to post
Share on other sites
Quote:

a.) Generic static methods are not possible

That's not true; C# explicitly supports generic static methods. When invoking the static method, you just need to provide the concrete type at the call site:


public class Carton<T>
{
public static T LookInside(T item)
{
// ...
}
}

// Need to provide concrete types for resolution to a specific type to occur.
int contents1 = Carton<int>.LookInside(5);
string contents2 = Carton<string>.LookInside("What's in here?");
bool contents3 = Carton<bool>.LookInside(false);



HTH,

Share this post


Link to post
Share on other sites
Quote:
Original post by kSquared
Quote:

a.) Generic static methods are not possible

That's not true; C# explicitly supports generic static methods. When invoking the static method, you just need to provide the concrete type at the call site:

*** Source Snippet Removed ***

HTH,



Ahh, THank you two!

Okay, I read that in a tutorial. Ttank you :)



Is Template overloading possible? I mean:

public static T DoSMT<float>( T t ){}
public static T DoSMT<int>( T t ){}

Share this post


Link to post
Share on other sites
Quote:
Is Template overloading possible? I mean:
*** Source Snippet Removed ***

Unfortunately, no. Just to be clear, C# supports generics, not templates. There's a difference between those two. Generics do not allow user-defined specializations.

Also, two quick corrections. First, your examples:

public static T DoSMT<float>( T t ){}
public static T DoSMT<int>( T t ){}

would not compile because you've specified the return type as T, but nothing is returned (compile-time error). Second, you call this "template overloading", but this is actually called "template specialization". I like to be a stickler for that kind of thing. :)

HTH,

Share this post


Link to post
Share on other sites
For my projects I use quite a flexible workaround:

A static class that is a kind of registry for pseudo-specializations:

public static class Arithmetics<T> {
public delegate T Binary(T value1, T value2);
public delegate T Unary(T value);

#region Add
static Binary add;

public static Binary AddHandler {
get { return add; }
set { add = value; }
}

public static T Add(T value1, T value2) {
System.Diagnostics.Debug.Assert( add != null, "No add-handler for " + typeof( T ) + " registered" );
return add( value1, value2 );
}
#endregion


#region Subtract
static Binary subtract;

public static Binary SubtractHandler {
get { return subtract; }
set { subtract = value; }
}

public static T Subtract(T value1, T value2) {
System.Diagnostics.Debug.Assert( subtract != null, "No subtract-handler for " + typeof( T ) + " registered" );
return subtract( value1, value2 );
}
#endregion


#region Invert
static Unary invert;

public static Unary InvertHandler {
get { return invert; }
set { invert = value; }
}

public static T Invert(T value) {
System.Diagnostics.Debug.Assert( invert != null, "No invert-handler for " + typeof( T ) + " registered" );
return invert( value );
}
#endregion
// and so on
}





Similarly, a registry for conversion routines:

static class Conversion<From, To>
{
static Converter<From, To> converter;

public static Converter<From, To> Converter {
get { return converter; }
set { converter = value; }
}

public static To Convert(From value) {
System.Diagnostics.Debug.Assert( converter != null,
"No converter from " + typeof(From) + " to " + typeof(To) + " registered");
return converter( value );
}
}






These can be used by the vertex struct or any other generic type

struct Vector3<T> {
public T X, Y, Z;

public Vector3(T x, T y, T z) {
X = x; Y = y; Z = z;
}

public override string ToString() {
return string.Format( "[{3}] x:{0}, y:{1}, z:{2}",
X.ToString(),
Y.ToString(),
Z.ToString(),
typeof(T).Name );
}


public static Vector3<T> operator +(Vector3<T> a, Vector3<T> b) {
return new Vector3<T>(
Arithmetics<T>.Add( a.X, b.X ),
Arithmetics<T>.Add( a.Y, b.Y ),
Arithmetics<T>.Add( a.Z, b.Z ) );
}

public static Vector3<T> operator -(Vector3<T> a, Vector3<T> b) {
return new Vector3<T>(
Arithmetics<T>.Subtract( a.X, b.X ),
Arithmetics<T>.Subtract( a.Y, b.Y ),
Arithmetics<T>.Subtract( a.Z, b.Z ) );
}

public static Vector3<T> operator -(Vector3<T> a) {
return new Vector3<T>(
Arithmetics<T>.Invert( a.X ),
Arithmetics<T>.Invert( a.Y ),
Arithmetics<T>.Invert( a.Z));
}

// cool! convert to a vector of another type!
public Vector3<U> Convert<U>() {
return new Vector3<U>(
Conversion<T, U>.Convert( X ),
Conversion<T, U>.Convert( Y ),
Conversion<T, U>.Convert( Z ) );
}
}





All I have to do is to register handlers that perform the (specialized) operations:

static void Main() {
// register arithmetic and conversion-handlers
Arithmetics<float>.AddHandler = delegate(float a, float b) { return a + b; };
Arithmetics<float>.SubtractHandler = delegate(float a, float b) { return a - b; };
Arithmetics<float>.InvertHandler = delegate(float a) { return -a; };
Conversion<float, double>.Converter = delegate(float value) { return value; };

// now we are ready to use the vector
Vector3<float> fv1 = new Vector3<float>( 1, 2, 3 );
Vector3<float> fv2 = new Vector3<float>( 2, 3, 4 );
Vector3<float> result = fv1 + fv2;
Vector3<double> converted = result.Convert<double>();

Console.WriteLine( fv1 );
Console.WriteLine( fv2 );
Console.WriteLine( result );
Console.WriteLine( converted );

Console.ReadKey();
}





I've seen other solutions that involved some kind of primitive-wrapper-structs implementing a IArithmetic<T> kind of interface. However, I find my solution to be much cleaner and easier to extend.

Pros:
A quite clean solution that does not need a huge amount of extra wrapper-classes. It can be extended quite simply by adding new handler. Handlers can even be exchanged at runtime for whatever reason.

Cons:
There's a performance penalty when calling delegates, so be sure to benchmark different solution. Neither is this implementation thread- or crossdomain-safe. Well, it's just the way I do it. Another drawback is that the presence of a required handler is only checked at runtime (here I use assertions).

Regards,
Andre


P.S.: [rant]I tried to port this to Java. However, there it seems generics are supported on instances only. One more reason why I like C# better than Java[/rant]
P.P.S.: This technique can be extended to be used for generic double dispatching, e.g. for bounding-volume intersection or scenegraphs. For those of you capable of German I wrote this down in an article

Share this post


Link to post
Share on other sites
Quote:

Would not compile because you've specified the return type as T, but nothing is returned (compile-time error).

I know! ;)

[qoute]
Second, you call this "template overloading", but this is actually called "template specialization". I like to be a stickler for that kind of thing. :)
[/qoute]
Okay, im not used to "Programming- English". Thank you! :)


Quote:
Original post by VizOne
For my projects I use quite a flexible workaround:
href="http://gentlestorm.de/blog/articles/214.aspx">article

Wow! Nice solution! Do you know how fast it is? I mean will it be alot slower than a spezialised solution? ( I mean 1000+ numeric operations each frame. )



Quote:

To change your LIB environment variable, right-click your "My Computer" icon and select "properties". Then click the "Advanced" tab, and click on the "Environment Variables" button. There you will see a list of environment variables and they're values. You can modify them there. You may have to restart Visual Studio for the change to take effect.


Ah! Well the problem is that I can't find a FrameworkSDK\Lib\ folder. Any ideas where it should be? I have CompactFrameworkSDK\ folder in my old VS2003 install.

Help :o

Thank you! See you later.

[Edited by - Riddle on December 18, 2004 6:14:12 PM]

Share this post


Link to post
Share on other sites
The main problem I've faced in using generics for numeric types is that you can't invoke arithmetic operators on objects of the types specified as generic parameters. VizOne's solution is interesting; however, I don't believe it would be suitable for a lot of numeric operations you might need to do in most real-time games. The amount of dynamic binding and indirection going on is just too costly, and all of that overhead can add up to a lot for things like numerics which are used frequently. That said, VizOne's solution looks great for higher-level systems, like implementing a double-dispatch mechanism for collision detection between different primitive types.

Generics are also, unfortunately, not CLS compliant. If you're working on a CLS compliant .NET codebase, you should always provide alternatives to generic types and methods in your class libraries.

Our solution was to build a tier generator to generate all of the different variances in Vector, Matrix, and other numeric types from common script files. I'm also looking at providing a special numeric extensions library for C++/CLI that uses C++ templates.

Share this post


Link to post
Share on other sites
Hello all! :)

Just found this:

http://www.codeproject.com/csharp/genericnumerics.asp


I think the 2nd implementation is better than VizOnes solution. VizOne solution is higher level. It supports changing the operations at runtime.

The most important thing about the http://www.codeproject.com/csharp/genericnumerics.asp
solution is that it doesn't create extra overhead.


Well, what do you guys think? 1. Spezialised versions 2. generic interfaces or 3. generic delegates ?

Thank you! :)

Share this post


Link to post
Share on other sites
Yes, the second solution in the article is great and likely to perform much better than my solution. Actually, I don't use my solution in my project exactly in the way I posted but on a much higher level, i.e. with more chunky, batch-like calls, where the per-call overhead is negligable.

However, there's one disadvantage with the solution on code-project: the vector class would have to be instantiated like:


Vector<float, FloatCalculator> v = new Vector<float, FloatCalculator>(...);


which looks not very nice to me. (The solve this with a using-alias - but I'd like to have a cleaner solution)

I can't see a work-around here that would not use a virtual call (besides "using"). Of course you could have a static variable in the Vector-struct of type ICalculator<T> which is initialized once for each T that is used. However, this would result in virtual calls. Any solutions here?

Regards,
Andre

Share this post


Link to post
Share on other sites
Quote:
Original post by VizOne
Yes, the second solution in the article is great and likely to perform much better than my solution. Actually, I don't use my solution in my project exactly in the way I posted but on a much higher level, i.e. with more chunky, batch-like calls, where the per-call overhead is negligable.

However, there's one disadvantage with the solution on code-project: the vector class would have to be instantiated like:


Vector<float, FloatCalculator> v = new Vector<float, FloatCalculator>(...);


which looks not very nice to me. (The solve this with a using-alias - but I'd like to have a cleaner solution)

I can't see a work-around here that would not use a virtual call (besides "using"). Of course you could have a static variable in the Vector-struct of type ICalculator<T> which is initialized once for each T that is used. However, this would result in virtual calls. Any solutions here?

Regards,
Andre


According to the article, even though the type parameters for the generic struct are constrained to an interface, all method calls through that interface are statically bound (and thus inlined). I recall doing some benchmarks a long time ago where this wasn't the case (they were dynamically bound), but it looks like the performance of the CLR has been improved since then.

But I understand what you're getting... how do we get rid of that FloatCalculator parameter? If our Vector was a class type, then we could inherit from an abstract base class version of FloatCalculator that has all of it's methods protected and non-virtual.

public class Vector<T> : Calculator<T>
{
...
}

But that would only work for if Vector is indeed a class, which probably isn't good for the performance of the system. Better to keep it as a struct. And I don't know if there's a solution for value types.

[Edit: It just occurred to me this wouldn't work, it doesn't let you specify a specialization of ICalculator<T> like SingleCalculator or DoubleCalculator.]

But, all of this new stuff still doesn't remove the fact that generics are not CLS compliant. For a CLS compliant assembly, you still need to provide non-generic alternatives to any public generic classes--or just abstain from using generics in the first place (for the public interfaces of types, nothing wrong with using it internally).

Share this post


Link to post
Share on other sites
::But, all of this new stuff still doesn't remove the fact that generics are
::not CLS compliant.

WHich has changed. Generics are now in the CLS subset - people maintaining CLS langauges have to move. The change was published this week.

Share this post


Link to post
Share on other sites
Quote:
Original post by thona
::But, all of this new stuff still doesn't remove the fact that generics are
::not CLS compliant.

WHich has changed. Generics are now in the CLS subset - people maintaining CLS langauges have to move. The change was published this week.


That is excellent news. I was unaware of that recent announcement, thanks for letting us know.

Share this post


Link to post
Share on other sites

This topic is 4737 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this