Re: float algorithm is slow
On Sat, 09 Jul 2005 17:35:27 -0700, websnarf wrote:
[color=blue]
> Wenfei wrote:[color=green]
>> float percentage;
>> for (j = 0; j < 10000000; j++) {
>> percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
>> buffer[totalBytes] =ceilf(volume * percentage) + volume; totalBytes++;
>> }
>> }[/color]
> sinf() appears to be a Microsoft VC++ extension that computes sin() but
> uses only 32-bit floats. Interesting that the zealots in this newsgroup
> didn't call you on that.
>
> Ok, anyhow remembering our trigonometry:
>
> sin(a + b) = sin(a)*cos(b) + sin(b)cos(a) cos(a + b) = cos(a)*cos(b) -
> sin(b)sin(a)
>
> Now we can strength reduce the argument to sinf:
>
> arg += (freqency*2*3.1 4159/sampleFreq);
>
> But that value is a constant:
>
> arg += deltaAngle; /* deltaAngle is precomputed as:
> freqency*2*3.14 159/sampleFreq */
>
> So we can simplify this to:
>
> s1 = percentage*cos( deltaAngle) + c*sin(deltaAngl e);
> c = c*cos(deltaAngl e) + percentage*sin( deltaAngle);[/color]
You meant to subtract there, not add, I believe.
[color=blue]
> percentage = s1;
>
> And of course we can replace the cos(deltaAngle) and sin(deltaAngle) with
> some precomputed values, and we initialize c to 1, and percentage to 0.
>
> This removes all the trigonometric functions altogether.[/color]
Good suggestion. That would seem to be the major contributor to the
calculation time, although you'd have to compare the approaches to be
sure. It's theoretically possible that on a specially optimised machine
sin(j*deltaAngl e) could be faster than your approach, but I very much
doubt that this is the case on the OP's cell phone...
[color=blue]
> The problem is that it will have "accumulati ng accuracy" problems. These
> problems are not trivial, because you will lose the sin^2+cos^2=1
> property, which will start scaling your results (either upward or
> downward) globally, which could get bad.
>
> A simple way to mitigate this is to split the loop into groups of, say,
> 100 or 1000 at a time, and reset the parameters with their true
> mathematical value with the raw sin/cos functions:
>
> percentage = sinf (frequency * j * 2 * 3.14159 / sampleFreq); c
> = cosf (frequency * j * 2 * 3.14159 / sampleFreq);[/color]
Yes and you could tune the loop grouping number beforehand by looking at
how many cycles it takes before the values grow too inaccurate for
your needs.
<snip>
On Sat, 09 Jul 2005 17:35:27 -0700, websnarf wrote:
[color=blue]
> Wenfei wrote:[color=green]
>> float percentage;
>> for (j = 0; j < 10000000; j++) {
>> percentage = sinf(frequency * j * 2 * 3.14159 / sampleFreq );
>> buffer[totalBytes] =ceilf(volume * percentage) + volume; totalBytes++;
>> }
>> }[/color]
> sinf() appears to be a Microsoft VC++ extension that computes sin() but
> uses only 32-bit floats. Interesting that the zealots in this newsgroup
> didn't call you on that.
>
> Ok, anyhow remembering our trigonometry:
>
> sin(a + b) = sin(a)*cos(b) + sin(b)cos(a) cos(a + b) = cos(a)*cos(b) -
> sin(b)sin(a)
>
> Now we can strength reduce the argument to sinf:
>
> arg += (freqency*2*3.1 4159/sampleFreq);
>
> But that value is a constant:
>
> arg += deltaAngle; /* deltaAngle is precomputed as:
> freqency*2*3.14 159/sampleFreq */
>
> So we can simplify this to:
>
> s1 = percentage*cos( deltaAngle) + c*sin(deltaAngl e);
> c = c*cos(deltaAngl e) + percentage*sin( deltaAngle);[/color]
You meant to subtract there, not add, I believe.
[color=blue]
> percentage = s1;
>
> And of course we can replace the cos(deltaAngle) and sin(deltaAngle) with
> some precomputed values, and we initialize c to 1, and percentage to 0.
>
> This removes all the trigonometric functions altogether.[/color]
Good suggestion. That would seem to be the major contributor to the
calculation time, although you'd have to compare the approaches to be
sure. It's theoretically possible that on a specially optimised machine
sin(j*deltaAngl e) could be faster than your approach, but I very much
doubt that this is the case on the OP's cell phone...
[color=blue]
> The problem is that it will have "accumulati ng accuracy" problems. These
> problems are not trivial, because you will lose the sin^2+cos^2=1
> property, which will start scaling your results (either upward or
> downward) globally, which could get bad.
>
> A simple way to mitigate this is to split the loop into groups of, say,
> 100 or 1000 at a time, and reset the parameters with their true
> mathematical value with the raw sin/cos functions:
>
> percentage = sinf (frequency * j * 2 * 3.14159 / sampleFreq); c
> = cosf (frequency * j * 2 * 3.14159 / sampleFreq);[/color]
Yes and you could tune the loop grouping number beforehand by looking at
how many cycles it takes before the values grow too inaccurate for
your needs.
<snip>
Comment