Re: [LAD] Is -ffast-math safe for audio?

2018-11-24 Thread Fons Adriaensen
On Sat, Nov 24, 2018 at 10:49:46AM +, Will Godfrey wrote:

> >The safe way is of course:
> >
> >int i = (int) floorf (p);
> >float f = p - i;
 
> I'd been mulling over *exactly* that point for some time. My reasoning being
> that in the latter case, if the integer was slightly wrong then using it for
> the subtraction should give a remainder that was also slightly wrong, but in a
> direction that tends to compensate for the error.

How can an int be 'slightly wrong' ? :-)
The advantage of the 'safe' way is that you always have p == i + f.

> The other thing, is why do we need the floorf? Or in the original example
> (which was taken from working code) truncf?
> A straight cast to int seems to give exactly the same result, and is at least
> twice as fast with -O3 and about 4 times as fast unoptimised.

We want f >= 0, so rounding must be towards -inf. Casting will truncate
(i.e. round towards zero). This gives the correct result only if p >= 0.
That may be all you need, but I wouldn't like to depend  on it.

There is a way to avoid all float to int conversions, at least outside
the per-sample loops.

Suppose you have a wavetable of size L, current position is float p,
and increment is float f. To generate N samples you'd have something
like:


for (i = 0; i < N; i++)
{
k = floorf (p);
u = p - k;

// use k, u to interpolate in wavetable

p += f;
if (p >= L) p -= L;
}

To avoid floorf() inside the loop, instead of maintaining p and f
as floats, split both of them from the start into an integer and
float part:

k = floorf (p);
u = p - k;

kf = floorf (f);
uf = f - kf;

for (i = 0; i < N; i++)
{
// use k, u to  interpolate in wavetable

k += kf;
u += uf;
if (u >= 1.0f) 
{
k += 1;
u -= 1;
}
if (k >= L) k -= L;
// or k &= L-1 if L is a power of 2.
}


Ciao,

-- 
FA



___
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
https://lists.linuxaudio.org/listinfo/linux-audio-dev


Re: [LAD] Is -ffast-math safe for audio?

2018-11-24 Thread Will Godfrey
On Sat, 24 Nov 2018 11:14:06 +0100
Fons Adriaensen  wrote:

>The dangerous thing to do is: 
>
>// given float p
>
>int i = (int) floorf (p);
>float f = fmodf (p, 1.0f);
>
>as you could end up with i + f != p.
>
>The safe way is of course:
>
>int i = (int) floorf (p);
>float f = p - i;
>
>
>Ciao,
>

Thanks very much for that Fons :)

I'd been mulling over *exactly* that point for some time. My reasoning being
that in the latter case, if the integer was slightly wrong then using it for
the subtraction should give a remainder that was also slightly wrong, but in a
direction that tends to compensate for the error.

The other thing, is why do we need the floorf? Or in the original example
(which was taken from working code) truncf?

A straight cast to int seems to give exactly the same result, and is at least
twice as fast with -O3 and about 4 times as fast unoptimised.

-- 
Will J Godfrey
http://www.musically.me.uk
Say you have a poem and I have a tune.
Exchange them and we can both have a poem, a tune, and a song.
___
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
https://lists.linuxaudio.org/listinfo/linux-audio-dev


Re: [LAD] Is -ffast-math safe for audio?

2018-11-24 Thread Fons Adriaensen
On Thu, Nov 22, 2018 at 11:29:11PM +0100, Robin Gareus wrote:

> A simpler example to show this is
> 
> #include 
> #include 
> int main (int argc, char** argv) {
>   float a = 0;
>   for (int i = 0; i < 100; ++i) {
> a += 0.1f;
> a -= 0.05f;
> a = fmodf (a, 1.f);
>   }
>   printf ("%f\n", a);
>   return 0;
> }
> 
> using gcc 6.3.0-18+deb9u1, x86_64, this
> prints 1.00 (when compiled with -O0)
> and0.01 (when compiled with -O2 --fast-math)

Actually 0.99940 and 0.00596.

The 1.00 would imply that the fmodf (a, 1.0f) would be
plain wrong, but it isn't.

The examples shown in this thread all involve converting
floats to ints. Typical application of this in audio is
to convert a float index into a wavetable to an int index
and a float < 1 interpolation argument.

The dangerous thing to do is: 

// given float p

int i = (int) floorf (p);
float f = fmodf (p, 1.0f);

as you could end up with i + f != p.

The safe way is of course:

int i = (int) floorf (p);
float f = p - i;


Ciao,

-- 
FA

___
Linux-audio-dev mailing list
Linux-audio-dev@lists.linuxaudio.org
https://lists.linuxaudio.org/listinfo/linux-audio-dev