Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Efficiently dividing a double by a power of 2

Tags:

c++

c

x86

I'm implementing a coherent noise function, and was surprised to find that using gradient noise (i.e. Perlin noise) is actually slightly faster than value noise. Profiling shows that the reason for this is the division needed to convert the random int value into a double of range -1.0 to 1.0:

static double noiseValueDouble(int seed, int x, int y, int z) {
    return 1.0 - ((double)noiseValueInt(seed, x, y, z) / 1073741824.0);
}

Gradient noise requires a few multiplies more, but due to the precomputed gradient table uses the noiseValueInt directly to compute an index into the table, and doesn't require any division. So my question is, how could I make the above division more efficient, considering that the division is by a power of 2 (2^30).

Theoretically all that would need to be done is to subtract 30 from the double's exponent, but doing that by brute force (i.e. bit manipulation) would lead to all sorts of corner cases (INF, NAN, exponent overflow, etc.). An x86 assembly solution would be ok.

like image 685
zennehoy Avatar asked Jan 19 '12 13:01

zennehoy


2 Answers

Declare a variable (or constant) with the inverse value and multiply by it, effectively changing the division to a multiplication:

static const double div_2_pow_30 = 1.0 / 1073741824.0;

Another way (utilizing the property that the number is a power of 2) is to modify the exponent with bit operations. Doing that will make the code dependant on doubles being stored using the IEEE standard which may be less portable.

like image 135
Klas Lindbäck Avatar answered Sep 20 '22 19:09

Klas Lindbäck


I'm not sure you can trust the profiling in here. For smaller, faster functions, the effect of the profiling code itself starts to skew the results.

Run noiseValueDouble and the corresponding alternative in a loop to get better numbers.

An x86 assembler solution is a bit-fiddling solution, you may as well do the bit fiddling in C. Fast power-of-two division instructions (bit shifts) only exist for integers.

If you really want to use special instructions, MMX it up or something.

like image 31
spraff Avatar answered Sep 23 '22 19:09

spraff