Skip to content

Commit 1067f26

Browse files
committed
ASE: mathutils.hh: improve fast_log2, add fast_log2_block
- avoid using a union in fast_log2 (fix undefined behaviour) - make code auto vectorizable by gcc - add a block version for fast_log2 (should be auto vectorized) - assume sign bit == 0, makes exponent extraction easier Signed-off-by: Stefan Westerfeld <stefan@space.twc.de>
1 parent da20031 commit 1067f26

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

ase/mathutils.hh

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
#include <ase/cxxaux.hh>
66

7+
#include <cstring>
8+
79
namespace Ase {
810

911
/// Double round-off error at 1.0, equals 2^-53
@@ -100,11 +102,15 @@ fast_exp2 (float ex)
100102
extern inline ASE_CONST float
101103
fast_log2 (float value)
102104
{
103-
// log2 (i*x) = log2 (i) + log2 (x)
104-
FloatIEEE754 u { value }; // v_float = 2^(biased_exponent-127) * mantissa
105-
const int i = u.mpn.biased_exponent - FloatIEEE754::BIAS; // extract exponent without bias
106-
u.mpn.biased_exponent = FloatIEEE754::BIAS; // reset to 2^0 so v_float is mantissa in [1..2]
107-
float r, x = u.v_float - 1.0f; // x=[0..1]; r = log2 (x + 1);
105+
const int EXPONENT_MASK = 0x7F800000;
106+
int iv;
107+
memcpy (&iv, &value, sizeof (float)); // iv = *(int *) &value
108+
int fexp = (iv >> 23) - FloatIEEE754::BIAS; // extract exponent without bias (rely on sign bit == 0)
109+
iv = (iv & ~EXPONENT_MASK) | FloatIEEE754::BIAS << 23; // reset exponent to 2^0 so v_float is mantissa in [1..2]
110+
float r, x;
111+
memcpy (&x, &iv, sizeof (float)); // x = *(float *) &iv
112+
x -= 1;
113+
// x=[0..1]; r = log2 (x + 1);
108114
// h=0.0113916; // offset to reduce error at origin
109115
// f=(1/log(2)) * log(x+1); dom=[0-h;1+h]; p=remez(f, 6, dom, 1);
110116
// p = p - p(0); // discard non-0 offset
@@ -115,7 +121,19 @@ fast_log2 (float value)
115121
r = x * (+0.45764712300320092992105460899527194244236573556309f + r);
116122
r = x * (-0.71816105664624015087225994551041120290062342459945f + r);
117123
r = x * (+1.44254540258782520489769598315182363877204824648687f + r);
118-
return i + r; // log2 (i) + log2 (x)
124+
return fexp + r; // log2 (i) + log2 (x)
125+
}
126+
127+
/** compute fast_log2 for a block of values
128+
*
129+
* This is often faster than computing individual values, because fast_log2 and this
130+
* function are written in a way that both, gcc and clang should auto vectorize it
131+
*/
132+
extern inline void
133+
fast_log2_block (float *values, int n_values)
134+
{
135+
for (int k = 0; k < n_values; k++)
136+
values[k] = fast_log2 (values[k]);
119137
}
120138

121139
} // Ase

0 commit comments

Comments
 (0)