Designing the Vector3D class

I don't know which is the best practice, when we want to create a new vector 3D class, I mean which of these two examples is the best way?

class Vec3D
{
   private:

         float m_fX;
         float m_fY;
         float m_fZ;

...
};

      

or

class Vec3D
{
   private:

         float m_vVec[3];
...
};

      

With the first aproach we have separate variables, we cannot be contiguous in memory, so the caches can fail, but accessing those variables is one instruction.

In the second aproach we have a vector of 3 contiguous floats in memory, the caches are fine here, but each access will make an additional amount of variable offset. Booty thinks this vectorial approach might better match optimizations like SSE2 / 3 or something.

Which aproach is better, I'm lost, I need advice :)

Thank you for your time:)

LLORENS

+2


source to share


13 replies


use

class Vec3D
{
   private:
    union 
    {
        float m_vVec[3];
        struct
        {
             float m_fX;
             float m_fY;
             float m_fZ;
        };
    };
    ...
}

      



it will give you both at no extra charge

+13


source


The second will make matrix operations much easier.



Before writing your own vector and matrix classes, you can review the code for something like openscengraph

+4


source


I would prefer the first approach because it will make your code more readable.

+2


source


I would go with the first one, mainly for readability reasons. It would be very easy to get lost in the equation if you have a lot of array indices, but if you have it explicitly as x, y, z then it's easier to understand what's going on.

+2


source


Both forms are identical in memory layout, unless your compiler has a very strange addition. Member elements will be put together if they are declared together in a class.

I'll make a choice based on the clarity of the code that will use the variables.

+2


source


Assuming you will be doing heavy computation with your vectors, I would suggest making your members public (or just using a struct instead of a class). You should skip the overhead of getters and just access the elements of the vector directly.

In terms of syntax, the first form is more readable. If you ever need access to members as an array of three values, you might also consider using a union, which gives you access to both individual members and the array.

+2


source


Option 3?

struct Vec3D
{
    // ...
}
      

+1


source


The more important question to ask yourself is, someday you will need to reference coordinates by indices, or call them x, y, and z sufficient.

+1


source


I am against the introduction of my own 3D class.

While such a class seems simple enough, it takes incredible work to create an efficient, reliable, reliable, and accurate class of this kind.

There is nothing worse than spending many hours looking for a weird error, only to end up finding that it is caused by a numerical instability in your vector class, generating the wrong answer for a specific input. Trust me, I was there!

There are many libraries available, reviewed and verified by thousands of users, so you can use them with confidence.

A library that I've used successfully for many years is Andrew Willmotts' simple vector library. http://www.cs.cmu.edu/~ajw/doc/svl.html

SVL is simple and straightforward. However, it does have a very outdated API and the problem for me is that this is another third party library that needs to be connected and downloaded by my clients.

So, lately I've been using boost :: uBLAS and in particular a fixed size vector wrapper based on the one described here: http://www.crystalclearsoftware.com/cgi-bin/boost_wiki/wiki.pl?Effective_UBLAS

The acceleration library is, as always, intimidating when you first approach it. However, it is superbly efficient and perfect, actively maintained and shipped for "free" when boost is added in your program anyway.

+1


source


From a performance standpoint, the compiler should be able to produce equally efficient code for both. However, there are pros and cons for both.

The first is by far the more readable. However, the second one allows you to grab the variable by index. So if you need to do something like adding all two vectors, this code will be simpler:

for(int i = 0; i < 3; ++i) {
    vVec[i] += o.vVec[i];
}

      

against.

m_fX += o.m_fX;
m_fY += o.m_fY;
m_fZ += o.m_fZ;

      

So, I would say no matter what you find more convenient and readable based on what you are trying to achieve.

0


source


I would definitely go for the second approach. In many places in your code, this will allow you to have an elegant loop instead of long repetition. Consider this:

for (int i = 0; i < 3; i++) {
  for (int j = 0; j < 3; j++) {
    VecMult.m_vVec[i] += Vec1.m_vVec[i] * Vec2.m_vVec[j];
}

      

Compared to this:

  VecMult.m_fX = Vec1.m_fX * Vec2.m_fX + Vec1.m_fX * Vec2.m_fY + Vec1.m_fX * Vec2.m_fZ;
  VecMult.m_fY = Vec2.m_fX * Vec2.m_fX + Vec2.m_fX * Vec2.m_fY + Vec2.m_fX * Vec2.m_fZ;
  VecMult.m_fZ = Vec3.m_fX * Vec2.m_fX + Vec3.m_fX * Vec2.m_fY + Vec3.m_fX * Vec2.m_fZ;

      

0


source


Both have pros and cons. We usually v1.X * v2.Y

read further v1[0] * v2[1]

. But there are algorithms that index the vector, and write in the second v1[a] * v2[b]

. In this case, the first solution will cause ugly blocks if

or switch

. I'm not a C ++ programmer, but maybe you could get the most out of two using macros or whatever C ++ supports (a union

, as others suggested, seems like a good candidate). In C #, I would create something like the following using properties.

public class Vector
{
    private readonly Single[] components = new Single[3];

    public Single X
    {
        get { return components[0]; }
        set { this.components[0] = value; }
    }

    public Single Y { ... }
    public Single Z { ... }
}

      

Finally, I believe that performance will not be an issue as indexing can be handled by CPU address computation units.

0


source


I would use the second (array) approach for the simple fact that it allows STL algorithms to implement member functions.

For example:

#include <cmath>
#include <numeric>

float Vec3D::Magnitude()
{
   return std::sqrt(std::inner_product(m_vVec, m_vVec + 3, m_vVec, 0.0f));
}

      

0


source







All Articles