# [Mesa-dev] [PATCH 03/13] gallium/auxiliary: Use exp2(x) instead of pow(2.0, x).

Roland Scheidegger sroland at vmware.com
Tue Jul 14 20:55:47 PDT 2015

```Am 14.07.2015 um 04:03 schrieb Matt Turner:
> On Mon, Jul 13, 2015 at 5:13 PM, Roland Scheidegger <sroland at vmware.com> wrote:
>> Did you replace 2 of them by exp2f but one by exp2f on purpose?
>
> Yes, two of them are converting their results to floats so they were
> converted to exp2f().
>
> Upon inspection, the argument of the one exp2 is just an integer...
> can't we convert that to (double)(1 << arg)?

Actually I believe the use of a double there is fully unwarranted (the
thing always has the form (2^x thus it's precise as a float anyway).
Pretty sure the rest of the math could do with floats too (there's only
a couple of floors plus some divs which are going to be exact too, I
don't think it would make a difference anywhere).
A straight shift won't work though since the exponent is between [-24,7].
Something like this should do:
float denom;
union fi expfi;
expfi.ui = (127 + exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS)
<< 23;
denom = expfi.f;

Though you could of course do the rest of the math denom is used for
(all slow divisions) with spiffy exponent hacking too.
Or maybe optimize just a little to get rid of the divisions by using
reverse denom (as the exponent hacking always looks a bit annoying...)
denom = pow(2, exp_shared - RGB9E5_EXP_BIAS - RGB9E5_MANTISSA_BITS);

maxm = (int) floor(maxrgb / denom + 0.5);
if (maxm == MAX_RGB9E5_MANTISSA+1) {
denom *= 2;
exp_shared += 1;
assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP);
} else {
assert(maxm <= MAX_RGB9E5_MANTISSA);
}

rm = (int) floor(rc / denom + 0.5);
gm = (int) floor(gc / denom + 0.5);
bm = (int) floor(bc / denom + 0.5);

Do

float revdenom;
union fi expfi;
/* add some insightful comment here what this does... */
expfi.ui = (127 - exp_shared + RGB9E5_EXP_BIAS +
RGB9E5_MANTISSA_BITS) << 23;
revdenom = expfi.f;

maxm = (int) floorf(maxrgb * revdenom + 0.5);
if (maxm == MAX_RGB9E5_MANTISSA+1) {
revdenom *= 0.5;
exp_shared += 1;
assert(exp_shared <= RGB9E5_MAX_VALID_BIASED_EXP);
} else {
assert(maxm <= MAX_RGB9E5_MANTISSA);
}

rm = (int) floorf(rc * revdenom + 0.5);
gm = (int) floorf(gc * revdenom + 0.5);
bm = (int) floorf(bc * revdenom + 0.5);

I bet that should be like 10 times as fast, though avoiding the double
promotion is just the icing on the cake...

Roland

>
>> I don't think we can use exp2/exp2f in gallium. This requires msvc 2013
>> (all of exp2, exp2f, powf are c99, powf is supported by older msvc but
>> the others are not). I guess though could throw some wrappers into
>> c99_math.h.
>
> Yeah, if we need to put wrappers in c99_math.h I can do that.
>

```