Skip to content

Instantly share code, notes, and snippets.

@i-e-b
Created March 23, 2023 11:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save i-e-b/8e991bb669c50e143eb0c53c0e7b308f to your computer and use it in GitHub Desktop.
Save i-e-b/8e991bb669c50e143eb0c53c0e7b308f to your computer and use it in GitHub Desktop.
compute log2(x) by reducing x to [0.75, 1.5)
// From https://tech.ebayinc.com/engineering/fast-approximate-logarithms-part-i-the-basics/
float fastlog2(float x) // compute log2(x) by reducing x to [0.75, 1.5)
{
// a*(x-1)^2 + b*(x-1) approximates log2(x) when 0.75 <= x < 1.5
const float a = -.6296735;
const float b = 1.466967;
float signif, fexp;
int exp;
float lg2;
union { float f; unsigned int i; } ux1, ux2;
int greater; // really a boolean
/*
* Assume IEEE representation, which is sgn(1):exp(8):frac(23)
* representing (1+frac)*2^(exp-127) Call 1+frac the significand
*/
// get exponent
ux1.f = x;
exp = (ux1.i & 0x7F800000) >> 23;
// actual exponent is exp-127, will subtract 127 later
greater = ux1.i & 0x00400000; // true if signif > 1.5
if (greater) {
// signif >= 1.5 so need to divide by 2. Accomplish this by
// stuffing exp = 126 which corresponds to an exponent of -1
ux2.i = (ux1.i & 0x007FFFFF) | 0x3f000000;
signif = ux2.f;
fexp = exp - 126; // 126 instead of 127 compensates for division by 2
signif = signif - 1.0; // <
lg2 = fexp + a*signif*signif + b*signif; // <
} else {
// get signif by stuffing exp = 127 which corresponds to an exponent of 0
ux2.i = (ux1.i & 0x007FFFFF) | 0x3f800000;
signif = ux2.f;
fexp = exp - 127;
signif = signif - 1.0; // <<--
lg2 = fexp + a*signif*signif + b*signif; // <<--
}
// lines marked <<-- are common code, but optimize better
// when duplicated, at least when using gcc
return(lg2);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment