0

I recently asked a question about structs, and optimizing some overloaded operators.

The original question is here

Now, I have taken those improvements to heart (or some/most of them), and I return with the following functions (nonmember functions, as I wish for them to be C compliant if possible).

inline Vector2& operator+=(Vector2 &a, const Vector2 &b)
{
    a.x += b.x;
    a.y += b.y;
    return a;
}

inline Vector2 operator+(Vector2 a, const Vector2 &b) 
{
    a += b;
    return a;
}

inline Vector2& operator*=(Vector2 &a, const float &n)
{
    a.x *= n;
    a.y *= n;
    return a;
}

inline Vector2 operator*(Vector2 a, const float &n) 
{
    a *= n;
    return a;
}

inline float operator*(const Vector2 &a, const Vector2 &b)
{
    return (a.x * b.x) + (a.y * b.y);
}

inline Vector2 rotate(const Vector2 &a, const float &angle)
{
    Vector2 out = a;
    out *= cos(angle);
    out.x -= sin(angle) * a.y;
    out.y += sin(angle) * a.x;
    return out;
}

(Please note, I omitted subtraction, and another multiplication operator, as they were equivalent to other operators listed here).

I am currently unable to notice any other potential improvements. Have I missed anything, that will (potentially) make these functions, as they currently stand, inefficient?

Community
  • 1
  • 1
Serge
  • 1,974
  • 6
  • 21
  • 33

2 Answers2

0

It is pointless to speak of improvements without profiling. However, there could be some room for improvement here:

inline Vector2 rotate(const Vector2& a, const float &angle) {
    Vector2 out = a;
    out *= cos(angle);
    const float sinA + sin(angle);
    out.x -= sinA * a.y;
    out.y += sinA * a.x;
    return out;
}

here, you cache the result of sin(angle) instead of calling the function twice. But I really have to stress that you should have a profiling system in place before trying any changes, so you can see whether they make a difference or not, and gauge whether any improvements are actually worthwhile. The compiler might well optimize away things that seem to be inefficient when looking at the source code.

it is worth knowing about RVO and NRVO, copy ellision and, in C++11, move semantics. Also, see this relevant article.

EDIT: My original answer was badly broken and this one is significantly different.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • Do you have any suggestions on where to get a profiling system, or how to use one? If it helps, I am currently working with Visual Studio 10 (Ultimate). (Also, your above code is not the same as what I used; the copy is required, because we need to retain the original elements from a, even after we *= by cos(angle). Unless I am missing something that you know.) Thank you! – Serge May 21 '12 at 06:23
  • @StefanZuefeldt the code is equivalent, you can test it. `a` is not modified because you are passing by value. As for profiling, I know nothing about VS. I have used gprof and valgrind on unix, plus plenty of hand written profiling tests. – juanchopanza May 21 '12 at 06:25
  • @StefanZuefeldt Visual Studio 2010 Ultimate has a built-in profiler. – Ilian May 21 '12 at 06:26
  • VS10 Ultimate brings comes bundled with a profiler. See this [MSDN starter guide on profiling](http://msdn.microsoft.com/en-us/library/ms182372.aspx) for more info – RedX May 21 '12 at 06:30
  • Thank you very much, for the information about the profilers. I shall look into this more. – Serge May 21 '12 at 06:30
  • Minor nitpick: there is no object `a` in the code, so accessing `a.y` or `a.x` will fail. You probably meant `out.x` and `out.y` instead. – Frerich Raabe May 21 '12 at 08:26
  • @FrerichRaabe you're right, my code is totally broken! I will fix or remove. – juanchopanza May 21 '12 at 08:33
  • @StefanZuefeldt sorry, but my original was wrong, as you suspected. I have added some more useful links, and a different optimization to your rotate function, but you may want to reconsider your acceptance of the answer., since it has changed significantly – juanchopanza May 21 '12 at 08:59
  • No need, your current answer and your previous one were both good enough for me! Thank you very much! – Serge May 21 '12 at 15:22
  • @juanchopanza As far as profiling and testing goes, would looking at the assemblies of two functions with equivalent results, and comparing the number of instructions executed, be a reliable method to determine which implementation is better? (while taking into account jumps and branches... which would produce a minimum and maximum instruction count... and in a situation where no given branch has any advantage over another) – Serge May 21 '12 at 19:43
0

I also find your + and * operators strange. You bring in a by value, modify it in operator, then copy it to result (and return it by value). It is possible that compiler optimizes this (not sure though). Doing it by the book could be faster, so maybe something like this?

inline Vector2 operator+(Vector2 &a, const Vector2 &b) 
{
    Vector2 r;
    r.x = a.x + b.x;
    r.y = a.y + b.y;
    return r;
}
dbrank0
  • 9,026
  • 2
  • 37
  • 55
  • Thank you for the suggestion; My original operators followed by a similar format (except they failed to use const or pass by reference XD). The reason I did this was to follow the rules of http://stackoverflow.com/questions/4421706/operator-overloading , under the "Binary Arithmetic Operators" section... since doing r = a + b apparantly creates a temporary value, (a + b), then copies it to r. However, += makes no extra copies, since everything is done by reference. I'd have to use profiling, like they said above, to be sure of what is best though. – Serge May 21 '12 at 15:22