Should i use a c++ Vector class?

Originally posted by Jambolo:
[b] [quote]

void cross_product_new (Vector3 a[restrict], const Vector3 b[restrict], const Vector3 c[restrict]);

which is equivalent to “a = b + c”, but WITHOUT temporaries or extra constructor invocations.

~velco[/b]<HR></blockquote>

Just make sure you don’t do this accidently or indirectly:

cross_product_new( a, a, b );

[/b][/QUOTE]

Sure, you gotta be careful . TANSTAAFL.

~velco

void cross_product_new (Vector3 a[restrict], const Vector3 b[restrict], const Vector3 c[restrict]);

which is equivalent to “a = b + c”, but WITHOUT temporaries or extra constructor invocations.
~velco

Sometimes, its faster to use temporaries. When there is no guarantee that memory being written is different from memory being read, the compiler must read/write every value from/to memory. With temporaries, frequently used values can be cached in registers.

For example, bar() is much faster than foo().

void foo( float *a, float *m, float *b )
{
a[0] = m[0]*b[0] + m[1]*b[1];
a[1] = m[2]*b[0] + m[3]*b[1];
}
void bar( float *a, float *m, float *b )
{
float x[2];
x[0] = m[0]*b[0] + m[1]*b[1];
x[1] = m[2]*b[0] + m[3]*b[1];
a[0] = x[0]; a[1] = x[1];
}

foo() generates 10 memory accesses and bar() generates only 8. This is because the compiler must worry that a[] overlaps m[] and b[] in foo(), but not in bar(). In bar(), x[0], x[1], b[0], and b[1] can be cached in registers.

In addition, bar() is more suited to parallel execution!

[This message has been edited by Jambolo (edited 07-12-2002).]

Which version of this vector function would be faster, or would it be the same speed?

inline void VectorAdd(vector3 a, vector3 b, vector3 result)
{
result[0] = a[0] + b[0];
result[1] = a[1] + b[1];
result[2] = a[2] + b[2];
}

inline void VectorAdd(const vector3 a, const vector3 b, vector3 result)
{
result[0] = a[0] + b[0];
result[1] = a[1] + b[1];
result[2] = a[2] + b[2];
}

Note: I doubt any of this is going to make any measurable performance difference, but I’m interested in the academics of it.

[This message has been edited by Junkstyle (edited 07-13-2002).]

There’s no difference in speed. Enforcement of const restraints is performed by the compiler at compile time, and has nothing to do with what gets done at execution time. Thus, the code that actually gets executed will be identical between the two versions, and there’ll be no speed difference.

[b]

[quote]

[quote]

void cross_product_new (Vector3 a[restrict], const Vector3 b[restrict], const Vector3 c[restrict]);

which is equivalent to “a = b + c”, but WITHOUT temporaries or extra constructor invocations.
~velco
[/QUOTE]

Sometimes, its faster to use temporaries. When there is no guarantee that memory being written is different from memory being read, the compiler must read/write every value from/to memory. With temporaries, frequently used values can be cached in registers.
[/b][/QUOTE]

Yes, that’s why I explicitly specified that the three arrays may not overlap.

For the case where the one of sources and the destination overlap, one can use the first function.

(FWIW, a third function is needed, when the result overlaps with the other parameter, as the cross product is not cimmutative )

~velco

[This message has been edited by velco (edited 07-13-2002).]

Originally posted by Citizen Thomas:
There’s no difference in speed. Enforcement of const restraints is performed by the compiler at compile time, and has nothing to do with what gets done at execution time.

While enforcement of the const-ness is indeed performed in compile time, it surely affects the code generation, probably not in these small functions, but where they are expanded.

~velco

Constant optimization?

Not really, no :wink: Or rather, sometimes, but not very often.

So I should go with the non-const version of VectorAdd() then?
It would allow me do a = a + b with one function call:

VectorAdd(a, b, a);

instead of having to do:

vector3 temp;
VectorAdd(a, b, temp);
VectorCopy(a, temp);

And don’t worry I use const for my VectorCross() function–thanks for looking out for me though.

One interesting point is John Carmack uses the VectorCopy version for all his vector functions like this. I’m lazy and don’t want to type an extra function call in all my formulas using vectors. The only thing I see the const version has going for it is the const correctness, i.e. if you have a const correct function that calls VectorAdd you wouldn’t have to call VectorCopy to make a copy of a const variable to input it into VectorAdd.

[This message has been edited by Junkstyle (edited 07-13-2002).]

Consider this:

class Point // or Vector, or whatever.
{
float xyz[3];
// other stuff
};

I find this a good approach because you can pass around your array to the vector forms of OpenGL commands e.g.

glVertex3fv(mypoint.xyz);

You can also use operator overloading, if it suits you. If not, then you can just use regular C functions like VectorAdd/Cross/Subract etc.

I find that it’s easier to deal with than straight float arrays.

-Mezz

Originally posted by harsman:
[b] Constant optimization?

Not really, no :wink: Or rather, sometimes, but not very often.[/b]

Not true. All this BS is based on the
assumption that the compiler has no aliasing
information. Compilers usualy do pointer
alias analysis. And, of course, there’s the
“restrict” keyword.

This one was particularly funny:
“If you’re getting true global optimization
anyway, then promising constness definitely
doesn’t help the optimizer do its job any
better in this respect.”

Just the opposite, global optimizations result in better aliasing information.

~velco

Mezz, I got an even better class setup for you:

class Vector3{
public:
union
{
float data[3];
struct
{
float x, y, z;
};
};
};

With that you can access your vector data either:

foo.x

or

foo.data[0]

I’m still writing my game demo with functions right now though cause I don’t want to redo it all but vector classes seem pretty cool to me.

Velco, I don’t think you understood Herb Sutter’s point. Usually, you compile one source file at a time and therefore the compiler has no knowledge of if a value that is const in the current translation unit is non-const somewhere else. Therefore the const won’t help much. And if the compiler does global optimzation, then it has aliasing information anyway so the const won’t make much of a difference either. That doesn’t mean const isn’t a good thing, being const correct is good. And if you declare a variable const from the start, then it probably enables optimization oppourtunities since the compiler can be certain it’s read only (barring const_cast<> of course).

Originally posted by harsman:
Velco, I don’t think you understood Herb Sutter’s point. Usually, you compile one source file at a time and therefore the compiler has no knowledge of if a value that is const in the current translation unit is non-const somewhere else.

Indeed. Howver global optimization means across function calls as opposed to one function at a time. And I have worked with at least two compilers, which can optimize the whole program, before linking. (of course, they re-generated the code from intermediate representation files, AFAICT).

[b]
Therefore the const won’t help much. And if the compiler does global optimzation, then it has aliasing information anyway so the const won’t make much of a difference either.
[b]

It ain’t so. One needs both pieces of information. A trivial example:

void foo(const float *);

a = b * c[i];
foo ©;
d = e * c[i];

Assuming, c is no aliased, the compiler can save assume that the value of c[i] is the same before and after the call, thus avoiding a second load by possibly using the register where it loaded c[i] the first time (will, “i” does not change too.

One can imagine the same for several elements of c, i.e., for a whole vector.

Also, the “non-changing” property may propagate further on. Some of the expressions (e.g. c[i]) may appear to be loop invariants, thus moved to the prologue. If the compiler can infer “b == e” the above expression become common subexpression and can be eliminated by doing “d = a”. Moreover, this assignment may be moved before the call, if this would result in better instruction scheduling. Etc., etc.

My point is, while “const” by itself is not of much use for an optimizer, it does not stand alone. Coupled with aliasing information is can be useful for almost all optimization phases, by enabling the optimizer to obtain more accurate solutions to the data-flow equations.


That doesn’t mean const isn’t a good thing, being const correct is good. And if you declare a variable const from the start, then it probably enables optimization oppourtunities since the compiler can be certain it’s read only (barring const_cast<> of course).

See, I understand what he said. All of it is true, under some assumptions. I claim that [i]the assumptions/[i] are false.

As for his point, indeed, I do not understand his point. Under some cirmustances “const” won’t give any advantage to the optmization phases? So, what? We wan’t use “const” for this reason? I don’t think so. Then what’s the purpose of the article, other than to make him feel good

~velco

My point was just that const probably won’t help optimization as much as you might think at first. It’s still good, but not a magic cure-all for optimization. Bah, I’m probably just generating confusion in the beginners forum :slight_smile: Use const kids! It’s good for ya. I’ll go away now and stop nitpicking :slight_smile:

Remember this question?

So I should go with the non-const version of VectorAdd() then?
It would allow me do a = a + b with one function call:

VectorAdd(a, b, a);

instead of having to do:

vector3 result;
VectorAdd(a, b, result);
VectorCopy(a, result);

I suggest using the const version.
Who cares about the extra work to make a temp value to hold the result. It just majorly sucks not having const correct fuctions. I’ve been taking the short cut and got up to my neck in problems and paranoia with not having it const correct. I’m going back and changing mine back to the const version.

Score 1 more point for the Vector Class folks.

[This message has been edited by Junkstyle (edited 07-15-2002).]

Actually I changed it all to const correct and it really doesn’t matter I found. My vector is in this format:

typedef float vector3[3];

so passing in a const array to a function doesn’t stop you from dereferencing it and assigning different values to the array.

There’s a difference between a const pointer and a pointer to a constant object.

const float* foo; //is a pointer to a const float
float* const bar; //is a const pointer to a float
const float* const spam; //is a const pointer to a const float

My guess is you’ve made the pointer to the array const but not the values. Try here for further clarification. Sorry if I confused you, being const correct is always good.

Originally posted by Junkstyle:
[b]Remember this question?

So I should go with the non-const version of VectorAdd() then?
It would allow me do a = a + b with one function call:

VectorAdd(a, b, a);

instead of having to do:

vector3 result;
VectorAdd(a, b, result);
VectorCopy(a, result);
[/b]

Have both, for the cases where you don’t want to clobber one of the operands.

~velco