Re: [LAU] OT(ish): Strange coding problem (audio related)

From: Philipp Überbacher <hollunder@email-addr-hidden>
Date: Sat Jan 29 2011 - 14:22:10 EET

Excerpts from fons's message of 2011-01-29 12:46:49 +0100:
> On Sat, Jan 29, 2011 at 12:07:12PM +0100, Philipp Überbacher wrote:
>
> > Took me a while to figure out that libm is part of glibc :)
>
> It isn't. But it lives in /lib, not /usr/lib

The glibc package seems to own it on my system. Anyway, I was searching
the web for libm, then looking for a header and so on, but it's pretty
clear now, it's installed by default and the header for C is math.h.

> > > k = (int)(log2(x) + 1e-6)
> >
> > log2() suffers from the same problem? I somewhat dislike the idea of
> > adding a constant.
>
> Everything floating point 'suffers from the same problem'.
> Even addition. (1/3.0 + 1/3.0 + 1/3.0 == 1.0) doesn't have
> to result in true.

I thought that log2() might use a different routine if the argument is a
power of 2. I guess that even if it does it's nothing to rely on because
another libm implementation might not do the same thing.

Why did you choose 1e-6 specifically?

> > > int m, k;
> > > for (k = 0, m = 1; m < x; k++, m <<= 1);
> > >
> > > which will round up if x is not a power of 2.
> >
> > Neat. I thought about it myself yesterday but my ideas weren't exactly
> > brilliant. One idea was to divide by 2, the other to use a small
> > lookup table for powers of 2. I don't really know about efficiency, but
> > I guess bit shifting is as efficient as it gets?
>
> It's a single CPU cycle on most processors, and on some (e.g. ARM)
> it can even be combined with other instructions.

Really nice, but I wonder whether it really matters at the end of the
day, simply because of optimisation. I tried to compare your variant
with the one from Peter Nelson using a nice little line I got from
Torben Hohn at some point. Without optimisation the output is quite
different, but beginning with -O2 the machine code appears all the same.

# simple variant using *= 2
echo "void a() { int m, k, j = 2048; for (k = 0, m = 1; m < j; k++, m *=
2); }" | gcc -O2 -xc -S - -o -

# Fons's variant
echo "void a() { int m, k, j = 2048; for (k = 0, m = 1; m < j; k++, m
<<= 1); }" | gcc -O2 -xc -S - -o -

# Peter Nelsons variant
echo "void a() { int m, k, j = 2048; for (k = 0; (1 << k) < j; k++); }"
| gcc -O2 -xc -S - -o -

To be honest I don't know what the line does exactly and hence whether
this is a valid comparison. Also, my knowledge of assembly is so minimal
that I have no idea where the computation takes place at all in the
optimised versions.

If the optimised code really is the same is it worth it to use funky bit
shifting operations? Especially Peter Nelsons version is non-obvious to
me (although it's probably the most efficient out of the three if no
optimisation is used).

_______________________________________________
Linux-audio-user mailing list
Linux-audio-user@lists.linuxaudio.org
http://lists.linuxaudio.org/listinfo/linux-audio-user
Received on Sat Jan 29 16:15:04 2011

This archive was generated by hypermail 2.1.8 : Sat Jan 29 2011 - 16:15:05 EET