Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading operator[] to start at 1 and performance overhead

I am doing some C++ computational mechanics (don't worry, no physics knowledge required here) and there is something that really bothers me.

Suppose I want to represent a 3D math Vector (nothing to do with std::vector):

class Vector {
    public:
        Vector(double x=0., double y=0., double z=0.) { 
            coordinates[0] = x;
            coordinates[1] = y;
            coordinates[2] = z;
        }
    private:
        double coordinates[3];
};

So far so good. Now I can overload operator[] to extract coordinates:

double& Vector::operator[](int i) {
     return coordinates[i] ;
}

So I can type:

Vector V; 

… //complex computation with V

double x1 = V[0];
V[1] = coord2;

The problem is, indexing from 0 is NOT natural here. I mean, when sorting arrays, I don't mind, but the fact is that the conventionnal notation in every paper, book or whatever is always substripting coordinates beginning with 1. It may seem a quibble but the fact is that in formulas, it always takes a double-take to understand what we are taking about. Of course, this is much worst with matrices.

One obvious solution is just a slightly different overloading :

double& Vector::operator[](int i) {
     return coordinates[i-1] ;
}

so I can type

double x1 = V[1];
V[2] = coord2;

It seems perfect except for one thing: this i-1 subtraction which seems a good candidate for a small overhead. Very small you would say, but I am doing computationnal mechanics, so this is typically something we couldn't afford.

So now (finally) my question: do you think a compiler can optimize this, or is there a way to make it optimize ? (templates, macro, pointer or reference kludge...)

Logically, in

double xi = V[i];

the integer between the bracket being a literal most of the time (except in 3-iteration for loops), inlining operator[] should make it possible, right ?

(sorry for this looong question)

EDIT:

Thanks for all your comments and answers

I kind of disagree with people telling me that we are used to 0-indexed vectors. From an object-oriented perspective, I see no reason for a math Vector to be 0-indexed because implemented with a 0-indexed array. We're not suppose to care about the underlying implementation. Now, suppose I don't care about performance and use a map to implement Vector class. Then I would find it natural to map '1' with the '1st' coordinate.

That said I tried out with 1-indexed vectors and matrices, and after some code writing, I find it not interacting nicely every time I use an array around. I thougth Vector and containers (std::array,std::vector...) would not interact often (meaning, transfering data between one another), but it seems I was wrong.

Now I have of a solution that I think is less controversial (please give me your opinion) : Every time I use a Vector in some physical context, I think of using an enum :

enum Coord {
    x = 0,
    y = 1,
    z = 2
};
Vector V;
V[x] = 1;

The only disadvantage I see being that these x,y and z can be redefined without enven a warning...

like image 354
Bérenger Avatar asked Aug 07 '12 22:08

Bérenger


2 Answers

Why not to try this:

class Vector {
    public:
        Vector(double x=0., double y=0., double z=0.) { 
            coordinates[1] = x;
            coordinates[2] = y;
            coordinates[3] = z;
        }
    private:
        double coordinates[4];
};

If you are not instantiating your object in quantities of millions, then the memory waist might be affordable.

like image 42
Kirill Kobelev Avatar answered Oct 05 '22 22:10

Kirill Kobelev


This one should be measured or verified by looking at the disassembly, but my guess is: The getter function is tiny and its arguments are constant. There is a high chance the compiler will inline the function and constant-fold the subtraction. In that case the runtime cost would be zero.

like image 51
usr Avatar answered Oct 06 '22 00:10

usr