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

## Recommended Posts

##### Share on other sites
try this

S3Dscalar operator*(const s3d_vec3& v)const{	return x*v.x + y*v.y + z*v.z;}

avoid passing by value if the functions are so short (and use const! :) )

EDIT: I've not seen the link to the code; now i've posted this hint

##### Share on other sites
The first thing I notice is that your functions are taking the vector arguments by value. This is not happy. Change the arguments to take the vectors by const reference. The second thing I notice is that you're overloading operator*() to do the dot-product. This can be non-intuitive. From a usability standpoint, I would consider eliminating this overload and just using your non-member function instead.

##### Share on other sites
As is usually the case in these situations you are creating unnecessary temporary objects. You should actually prefer to write your operators as non-member (possibly friend) functions and implement operatorX in terms of operatorX=, i.e.:
class SomeClass{	public:		SomeClass(float c, float d);		float a;		float b;};// we just modify an existing SomeClass objects, so pass and return by reference// and avoid creating any temporariesSomeClass & operator+=(SomeClass & lhs, SomeClass const & rhs){	lhs.a += rhs.a;	lhs.b += rhs.b;	return lhs;}// since we return a SomeClass by value we need to construct one in the function// we can take one parameter by value to automatically construct a new instanceSomeClass operator+(SomeClass lhs, SomeClass const & rhs){	return (lhs += rhs);}

But also take SiCrane's advice about operator* calculating the dot-product. It fails the test of least astonishment.

Enigma

##### Share on other sites
I will try your suggestions later today and benchmark the result.

Yeah, I thought the '*' = DOT was unintuitive too. The '*' had to be used for either the DOT product or the cross product, so I eventualy opted for the DOT product simply because I didn't want to waste the use of the operator, although neither really seamed intuitive.

##### Share on other sites
The results were close. With the optimizations suggested (and in release mode), straight C won, but by a very small margin. Out of 10000000 calculations per method, straight C scored 65 milliseconds, and operator overloading scored 69 milliseconds. The results were based on an average of 32 tests.

The source code:
	s3d_vec3 OOV1, OOV2, OOV3;	S3Dvec3f	CV1, CV2, CV3;	s3dVecSet3f(CV1, 0.0f, 1.0f, 0.0f);	s3dVecSet3f(CV2, 0.0f, 0.0f, 1.0f);	OOV1.Set(0.0f, 1.0f, 0.0f);	OOV2.Set(0.0f, 0.0f, 1.0f);	S3Duint	tick;	S3Duint	milli1=0, milli2=0;	S3Dfloat DOT;	S3Dchar string[128];	S3Duint j;	for(int i=0; i<32; i++)	{		tick=timeGetTime();		for(j=0; j<10000000; j++)		{			//s3dVecScale3f(CV2, CV1, 10.0f);			DOT=s3dVecDot3f(CV1, CV2);			//s3dVecCross3f(CV3, CV1, CV2);			//s3dVecNormalize3f(CV1);		}		milli1+=timeGetTime()-tick;		tick=timeGetTime();		for(j=0; j<10000000; j++)		{			DOT=OOV1*OOV2;			//OOV3.Cross(OOV1, OOV2);			//s3dVecNormalize3f2(CV1);			//OOV1=1.0f;		}		milli2+=timeGetTime()-tick;	}	itoa(milli1/32, string, 10);	MessageBox(NULL, string, "Straight C", MB_OK);	itoa(milli2/32, string, 10);	MessageBox(NULL, string, "Operator Overloading", MB_OK);

The other vector routine results proved to come in just as close, but C always won. Using C over operator overloading is pretty much a toss up now. I could stick with C and be happy, or I could start using operator overloading and still be happy.

Thanks again for all your help!

##### Share on other sites
"Yeah, I thought the '*' = DOT was unintuitive too."

Then do not do it

"The '*' had to be used for either the DOT product or the cross product,"

No it didn't. It doesn't have to be used at all.

"so I eventualy opted for the DOT product simply because I didn't want to waste the use of the operator,"

AAAAAHHHHHHHHHHHH AAAHHHHHHHHHH my brain exploded
No operator is ever "wasted". Operators should only be used when they make total and complete sense. Using them because you think that you have to, or that you will be wasting them if you don't use them, just gives operator overloading a bad name and turns people against the concept.

"although neither really seamed intuitive."

A strong argument for not doing it.

Sometimes overloading operators is good. Other times it is bad. I could use / to tokenize strings but I don't, because doing so would be insane. I mean it actually makes sense kind of, what if I did this:

string s("hi I am a string");
string* sa = s/" "; //now sa points to an array of strings "divided" by " ".

Now see to some that makes sense, and there is a rational behind it, but it is crazy. Don't go down the slippery slope into cryptic nonsense code. Operator overloading exists to make code clearer, not to save typing.

##### Share on other sites
Quote:
 Original post by WhatEverThe results were close. With the optimizations suggested (and in release mode), straight C won, but by a very small margin. Out of 10000000 calculations per method, straight C scored 65 milliseconds, and operator overloading scored 69 milliseconds. The results were based on an average of 32 tests.The source code:*** Source Snippet Removed ***The other vector routine results proved to come in just as close, but C always won. Using C over operator overloading is pretty much a toss up now. I could stick with C and be happy, or I could start using operator overloading and still be happy.Thanks again for all your help!

You shouldn't even be seeing that much difference. With the source code:
#include <ctime>#include <iostream>class s3d_vec{	public:		void Set(float x_, float y_, float z_)		{			x = x_;			y = y_;			z = z_;		}		float x;		float y;		float z;};inline float operator*(s3d_vec const & lhs, s3d_vec const & rhs){	return (lhs.x * rhs.x) + (lhs.y * rhs.y) + (lhs.z * rhs.z);}typedef float S3Dvec3f[3];inline void s3dVecSet3f(S3Dvec3f vec, float x, float y, float z){	vec[0] = x;	vec[1] = y;	vec[2] = z;}inline float s3dVecDot3f(S3Dvec3f lhs, S3Dvec3f rhs){	return (lhs[0] * rhs[0]) + (lhs[1] * rhs[1]) + (lhs[2] * rhs[2]);}int main(){	s3d_vec oov1;	s3d_vec oov2;	oov1.Set(0, 1, 0);	oov2.Set(0, 0, 1);	S3Dvec3f cv1;	S3Dvec3f cv2;	s3dVecSet3f(cv1, 0, 1, 0);	s3dVecSet3f(cv2, 0, 0, 1);	float dotAccumulator = 0;	float times[2];	times[0] = std::clock();#if defined(CPP)	for (int i = 0; i < 1000000000; ++i)	{		dotAccumulator += oov1 * oov2;		oov1.Set(dotAccumulator, 1, 0);	}#else	for (int i = 0; i < 1000000000; ++i)	{		dotAccumulator += s3dVecDot3f(cv1, cv2);		s3dVecSet3f(cv1, dotAccumulator, 1, 0);	}#endif	times[1] = std::clock();#if defined(CPP)	std::cout << "OOP: " << (times[1] - times[0]) << '\n';#else	std::cout << "C:   " << (times[1] - times[0]) << '\n';#endif	return dotAccumulator;}

I get the following results:
Borland:
OOP: 23469
C: 23469

Gcc:
OOP: 13843
C: 13859

Visual C++:
OOP: 4250
C: 4265

The small differences there are almost certainly down to the precision of the timer.

Enigma

##### Share on other sites
Glak, I know you're right. I was just so excited to finaly use operater overloading I didn't care how it was implimented, I just wanted to see if I could get it to work. It was my first time implimenting it, so it was mostly an experiment.

Enigma, you have quite an arsonal there! I would agree with your results, but when I conducted the test, the C versus CPP versions were varying dramaticly. So I figured it was the OS doing its preemtive multitasking. So I decided to work with an average instead of one cycle to allow both methods to share any lag from the OS. Let me know what you think.

The different compilers results are insain!...and I can't spell!!!

1. 1
Rutin
34
2. 2
3. 3
4. 4
5. 5

• 12
• 14
• 9
• 9
• 9
• ### Forum Statistics

• Total Topics
633331
• Total Posts
3011399
• ### Who's Online (See full list)

There are no registered users currently online

×