Speed up vector class
I wrote a test vector class and tried to optimize it. I have already reached quite good performance, I think. Can I somehow get more performance?
Here''s the code.
typedef float VVal;
class TVector
{
public:
TVector(){};
TVector(VVal aX, VVal aY, VVal aZ): X(aX), Y(aY), Z(aZ) {};
VVal X;
VVal Y;
VVal Z;
inline TVector operator+(const TVector& V)
{return TVector(X + V.X, Y + V.Y, Z + V.Z);};
inline TVector operator-(const TVector& V)
{return TVector(X - V.X, Y - V.Y, Z - V.Z);};
inline TVector operator*(const VVal f)
{return TVector(X * f, Y * f, Z * f);};
inline TVector operator/(const VVal f)
{return TVector(X / f, Y / f, Z / f);};
inline TVector& operator+=(const TVector& V)
{X += V.X; Y += V.Y; Z += V.Z; return *this;};
inline TVector& operator-=(const TVector& V)
{X -= V.X; Y -= V.Y; Z -= V.Z; return *this;};
inline TVector& operator*=(const VVal f)
{X *= f; Y *= f; Z *= f; return *this;};
inline TVector& operator/=(const VVal f)
{X /= f; Y /= f; Z /= f; return *this;};
inline bool operator==(const TVector& V) const
{return (X == V.X && Y == V.Y && Z == V.Z);};
inline bool operator!=(const TVector& V) const
{return !(X == V.X && Y == V.Y && Z == V.Z);};
inline bool operator<(const TVector& V) const
{return (CompareLength() < V.CompareLength());};
inline bool operator>(const TVector& V) const
{return (CompareLength() > V.CompareLength());};
inline bool operator<=(const TVector& V) const
{return (CompareLength() <= V.CompareLength());};
inline bool operator>=(const TVector& V) const
{return (CompareLength() >= V.CompareLength());};
inline VVal& operator[](int i)
{if (i == 0) return X; if (i == 1) return Y; return Z;};
inline friend ostream& operator<<(ostream& out, const TVector& v)
{
out << "(" << v.X << ", " << v.Y << ", " << v.Z <<")";
return out;
}
inline void Set(VVal aX, VVal aY, VVal aZ){X = aX; Y = aY; Z = aZ;};
inline VVal Length() const
{return sqrt(X * X + Y * Y + Z * Z);};
inline VVal CompareLength() const
{return X * X + Y * Y + Z * Z;};
};
inline VVal Dot(const TVector &v1, const TVector &v2)
{
return (v1.X * v2.X + v1.Y * v2.Y + v1.Z * v2.Z);
}
inline TVector Cross(const TVector &v1, const TVector &v2)
{
return TVector(v1.Y * v2.Z - v1.Z * v2.Y,
v1.Z * v2.X - v1.X * v2.Z,
v1.X * v2.Y - v1.Y * v2.X);
}
(Computer && !M$ == Fish && !Bike)
quote: Original post by Wunibald
inline TVector operator/(const VVal f)
{return TVector(X / f, Y / f, Z / f);};
You should replace this by:
inline TVector operator/(const VVAL f){ VVal inverse = 1.0 / f; return TVector(X * inverse, Y * inverse, Z * inverse);}
Apply to opetaror/=, too.
-Jussi
"It was nice to know you, who are you?"
(please forgive me if I sound picky! )
Hmm...can you check the generated assembly for the release build - are the temporaries being created for the arithmetic operators? Or are they being inlined?
Another thing that I can see is the two if statements in the operator [] function. Try this:
Now you can refer to the same data as either an array of floats, or three individual data members. And people say that unions are useless!
The last thing is the lack of const in some places of your class. Member functions that do not modify the class's data should have the word const after them:
So that they can be used on const objects. The four arithmetic operators (but not the assignment operators!) should be const, since they only build a temporary from the operation. Same with Length(), CompareLength(), Dot(), and Cross(). The parameters of the member functions should be const where possible, as I think this helps the compiler eliminate temporary variables.
- null_pointer
Sabre Multimedia
Edited by - null_pointer on October 27, 2000 8:56:01 AM
Hmm...can you check the generated assembly for the release build - are the temporaries being created for the arithmetic operators? Or are they being inlined?
Another thing that I can see is the two if statements in the operator [] function. Try this:
class TVector
{
public:
// this should be Standard C++. X, Y, and Z share the same
// memory as the three elements of the array, so you should
// be able to address the same memory either way. It should
// not require any changes to existing code, since X, Y, and
// Z appear as if they were in the class scope.
union
{
VVal array[3];
struct
{
VVal X;
VVal Y;
VVal Z;
};
};
// much simpler
inline VVal& operator[] (int x)
{ return( array[x] ); }
// const version used on const objects - can't modify the data
inline const VVal& operator[] (int x) const
{ return( array[x] ); }
};
Now you can refer to the same data as either an array of floats, or three individual data members. And people say that unions are useless!
The last thing is the lack of const in some places of your class. Member functions that do not modify the class's data should have the word const after them:
inline TVector operator+(const TVector V) const;
So that they can be used on const objects. The four arithmetic operators (but not the assignment operators!) should be const, since they only build a temporary from the operation. Same with Length(), CompareLength(), Dot(), and Cross(). The parameters of the member functions should be const where possible, as I think this helps the compiler eliminate temporary variables.
- null_pointer
Sabre Multimedia
Edited by - null_pointer on October 27, 2000 8:56:01 AM
Actually, I think an union would be the best solution to the [] operator. So, it would be written like this:
-Jussi
"I have no use for that; it''s ugly!"
union{ VVAl Data[3]; struct { VVal X; VVal Y; VVal Z; };};inline VVal& operator[](int i){ return Data<i>; };
-Jussi
"I have no use for that; it''s ugly!"
Copycat! hehe
No, actually Selkrank thought of it first, but I also figured it out and edited my post after he posted without knowing that he posted. If you can figure out what that means...
- null_pointer
Sabre Multimedia
No, actually Selkrank thought of it first, but I also figured it out and edited my post after he posted without knowing that he posted. If you can figure out what that means...
- null_pointer
Sabre Multimedia
@Selkrank:
Very good point! Thank you. I gain a lot of speed!
@null_pointer:
the operators are inlined. I had them in the *cpp file first (not inline). Then I compared them to the inlined version.
The inlined are much faster! So the inline works for operators.
Good point about the const on my operators.
But Length() and CompareLength() *are* already const.
The Dot() and Cross() function can''t be const, since the are no class members.
@both :0)
the union idea is elegant! (My first union) But the access isn''t that faster. About 0.00001% *g*.
Thany for your good ideas. I appreciate your inspiring influence.
Very good point! Thank you. I gain a lot of speed!
@null_pointer:
the operators are inlined. I had them in the *cpp file first (not inline). Then I compared them to the inlined version.
The inlined are much faster! So the inline works for operators.
Good point about the const on my operators.
But Length() and CompareLength() *are* already const.
The Dot() and Cross() function can''t be const, since the are no class members.
@both :0)
the union idea is elegant! (My first union) But the access isn''t that faster. About 0.00001% *g*.
Thany for your good ideas. I appreciate your inspiring influence.
(Computer && !M$ == Fish && !Bike)
Ah...yes, I see that now. I missed the closing brace of the class, and didn''t see about the Length() and CompareLength() functions. My mistake!
Happy Instantiating!
- null_pointer
Sabre Multimedia
Happy Instantiating!
- null_pointer
Sabre Multimedia
You know, I tried doing my vector class as inline at first myself but what I found out was that when vectors were used alot in another file, the compiler would *not* inline the code. When it did that, it created every function as a thiscall type and a performance difference was definitely noticeable.
Instead, I changed all method types to fastcall and I regained most all of my speed back. Unfortunatly though, it is no longer an inline class.
This is definitely something to lookout for because unless you pay attention to the assembly code created, you will probably not even know it happened until you notice that adding this one more function pushes you over the limit and the class is no-longer inlined.
Although, I suppose you could you forceinline if you really need the speed and don''t care so much about size. But then again, don''t forget about code/data cache problems either.
Regards,
Jumpster
Instead, I changed all method types to fastcall and I regained most all of my speed back. Unfortunatly though, it is no longer an inline class.
This is definitely something to lookout for because unless you pay attention to the assembly code created, you will probably not even know it happened until you notice that adding this one more function pushes you over the limit and the class is no-longer inlined.
Although, I suppose you could you forceinline if you really need the speed and don''t care so much about size. But then again, don''t forget about code/data cache problems either.
Regards,
Jumpster
Regards,JumpsterSemper Fi
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement
Recommended Tutorials
Advertisement