If you check the sources of the library libnoise, you can see the following code:
double noise::GradientNoise3D (double fx, double fy, double fz, int ix,
int iy, int iz, int seed)
{
// Randomly generate a gradient vector given the integer coordinates of the
// input value. This implementation generates a random number and uses it
// as an index into a normalized-vector lookup table.
int vectorIndex = (
X_NOISE_GEN * ix
+ Y_NOISE_GEN * iy
+ Z_NOISE_GEN * iz
+ SEED_NOISE_GEN * seed)
& 0xffffffff;
vectorIndex ^= (vectorIndex >> SHIFT_NOISE_GEN);
vectorIndex &= 0xff;
double xvGradient = g_randomVectors[(vectorIndex << 2) ];
double yvGradient = g_randomVectors[(vectorIndex << 2) + 1];
double zvGradient = g_randomVectors[(vectorIndex << 2) + 2];
// Set up us another vector equal to the distance between the two vectors
// passed to this function.
double xvPoint = (fx - (double)ix);
double yvPoint = (fy - (double)iy);
double zvPoint = (fz - (double)iz);
// Now compute the dot product of the gradient vector with the distance
// vector. The resulting value is gradient noise. Apply a scaling value
// so that this noise value ranges from -1.0 to 1.0.
return ((xvGradient * xvPoint)
+ (yvGradient * yvPoint)
+ (zvGradient * zvPoint)) * 2.12;
}
See the constant 2.12? Why the heck is it needed? It is even rational, no approximation of a real number.
If you think of it what guarantee do you have that the dot product dot(Q - P, G), where G is a unit gradient vector is going to be between -1 and 1?
EDIT:
I think he should be dividing by sqrt(2). The gradient vector can have any orientation and the P - Q vector can be parallel to it and be almost sqrt(2) size.