C/C++ Programming Tips (Generic)


Fast Float -> Int casts

(Mark Harris)
http://mega-nerd.com/FPcast/
So, a while back I was trying to get a lattice simulation to run as fast as
I could on a CPU. This type of simulation has a lot of loops of the type:

for (int k = 0; k < iResolutionZ; ++k)
for (int j = 0; j < iResolutionY; ++j)
for (int i = 0; i < iResolutionX; ++i)
// do stuff on latticeElement(i, j, k)

In some inner loops, part of the simulation (or visualization thereof) required casting the float values in the lattice to integers. I had read somewhere that this can be slow on Pentium class processors. It turns out it can be really slow, and smart people have figured out how to make it faster. It stands to reason that if you have a slow operation inside a loop that performs the operation millions of times, it is worth optimizing the slow operation (Amdahl's Law?). So I read what the smart people had to say: (http://mega-nerd.com/FPcast/), and grabbed some code that they had written, and got a rather large speed boost!

Here is the gist:

#include "float_cast.h"

int anInt;
float aFloat = 4.23e6;
double aDouble 3.14159;

// wherever you would normally do this:
anInt = (int) aFloat;
// or this:
anInt = (int) aDouble;

// Instead, do this:
anInt = lrintf(aFloat);
// or this (respectively)
anInt = lrint(aDouble);

Looks easy, right? Well, it appears that these functions aren't in the standard library included with MSVC. Luckily, the smart people have written some slick inline assembly to replace it, wrapped up to operate just like the functions above:

#if (defined (WIN32) || defined (_WIN32))
#include <math.h>
/* Win32 doesn't seem to have these functions.
** Therefore implement inline versions of these functions here.
*/
__inline long int
lrint (double flt)
{
int intgr;
_asm
{
fld flt
fistp intgr
} ;
return intgr ;
}

__inline long int
lrintf (float flt)
{
int intgr;
_asm
{
fld flt
fistp intgr
} ;
return intgr ;
}
#else

These give quite a big speedup over raw C casts, so if you are casting in your inner loops, use these instead. I've attached the "float_cast.h" file which includes the above code, and attempts to be portable (although it #includes a file that I don't have, and don't need on windows... Investigate the URL above for more info).

Mark

Simultaneous named and array access to Vector components

(Brandon Loyd)

It is sometimes nice to be able to access the components of a vector by
name:

somevec.x = 1.0;
somevec.y = .5;
somevec.z = 0;

It is also nice to be able to use array access inside loops:

for( int i=0; i < 3; i++ )
  somevec[i] = somefunc( i );

OpenGL often requires an array of floats as arguments:

float array[] = {1,1,1};
glLightf( GL_LIGHT0, GL_SPOT_DIRECTION, array );

If you implement your vector with explicit x,y,z variables, it is inconvenient to do array access. You have to basically do a switch on the index to return a reference to the right variable. In order to pass an array to the GL functions you have to first copy out all the values to an array - also a pain. On the other hand, if you implement your vector with an array it is easy to implement the latter 2 operations but a little awkward to implement named access. You have to use a function that returns a reference to the right array element or something like that.

With a union you get the best of both worlds.

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

  ...

  // read and write array accessors
  const float& operator[](int idx) const {return array[idx]; }
  float& operator[](int idx) { return array[idx]; }
 

 
  ...

};

With this vector you can have direct named access to the x,y,z members, easy array-style subscripting, and an easy way to pass the vector as an
array of floats to GL.

glLightf( GL_LIGHT0, GL_SPOT_DIRECTION, spotDirection.array );

This works on all compilers that I have tried (VC6, VC7, gcc, cc ) except icc, which doesn't like the unnamed structure.