Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   Optimizing pow() function (http://www.velocityreviews.com/forums/t960019-optimizing-pow-function.html)

 pozzugno@gmail.com 04-22-2013 03:23 PM

Optimizing pow() function

I have a simple (16-bit) embedded platform and I have to make the following calculations.

unsigned int
func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) {
return (unsigned int)(pow((double)adc, exp) *
(double)pwr / pow((double)pt, exp));
}

I noticed this calculation takes too much time, most probably for pow() function call and double conversion.

I'm finding a way to simplify/optimize this function. Consider that adc and pt parameters are in the range 0..1023, exp is in the range 1.00-3.00, and pwr can be 50-10000.

Any suggestion to avoid pow() function call?

 Eric Sosman 04-22-2013 03:42 PM

Re: Optimizing pow() function

On 4/22/2013 11:23 AM, pozzugno@gmail.com wrote:
> I have a simple (16-bit) embedded platform and I have to make the following calculations.
>
> unsigned int
> func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) {
> return (unsigned int)(pow((double)adc, exp) *
> (double)pwr / pow((double)pt, exp));
> }
>
> I noticed this calculation takes too much time, most probably for pow() function call and double conversion.
>
> I'm finding a way to simplify/optimize this function. Consider that adc and pt parameters are in the range 0..1023, exp is in the range 1.00-3.00, and pwr can be 50-10000.
>
> Any suggestion to avoid pow() function call?

Simple enough to avoid half of them:

return pwr * pow( (double)adc / (double)pt, exp);

This is "algebraically equivalent" to the original, although
it probably won't give exactly the same result every time.

--
Eric Sosman
esosman@comcast-dot-net.invalid

 Fred K 04-22-2013 06:22 PM

Re: Optimizing pow() function

On Monday, April 22, 2013 11:08:24 AM UTC-7, Rich Webb wrote:
> On Mon, 22 Apr 2013 08:23:51 -0700 (PDT), pozzugno@gmail.com wrote: >I have a simple (16-bit) embedded platform and I have to make the following calculations. > >unsigned int >func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) { > return (unsigned int)(pow((double)adc, exp) * > (double)pwr / pow((double)pt, exp)); >} > >I noticed this calculation takestoo much time, most probably for pow() function call and double conversion.. > >I'm finding a way to simplify/optimize this function. Consider that adc and pt parameters are in the range 0..1023, exp is in the range 1.00-3.00, and pwr can be 50-10000. > >Any suggestion to avoid pow() function call? You might try asking over in comp.arch.embedded, where this kind of an issue is more often addressed than here in a general C group. Depending on whatyou do with the result of func(), you might be able to get away with operating on the logarithms, applying Jack Crenshaw's bitlog() function as a fast approximation.

If pt is indeed in the range 0...1023, you have to handle the extreme case where pt=0 somehow, since the result is infinity, unless adc is also zero, in which case the result is indeterminant.
--
Fred K

 Edward A. Falk 04-22-2013 06:34 PM

Re: Optimizing pow() function

<pozzugno@gmail.com> wrote:
>I have a simple (16-bit) embedded platform and I have to make the following calculations.
>
>unsigned int
>func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) {
> return (unsigned int)(pow((double)adc, exp) *
> (double)pwr / pow((double)pt, exp));
>}
>
>I noticed this calculation takes too much time, most probably for pow() function call
>and double conversion.
>
>I'm finding a way to simplify/optimize this function. Consider that adc and pt
>parameters are in the range 0..1023, exp is in the range 1.00-3.00, and pwr can be
>50-10000.

Are you not worried about overflow?

Your embedded processor almost certainly does not have a floating-point
unit. This explains why your code is so slow.

I see all values are guaranteed to be integer values.

If you're not worried about overflow in the intermediate expressions,
or you can simplify your expression to reduce the risk, then consider
writing your own "ipow()" function.

--
-Ed Falk, falk@despams.r.us.com
http://thespamdiaries.blogspot.com/

 James Kuyper 04-22-2013 06:49 PM

Re: Optimizing pow() function

On 04/22/2013 02:34 PM, Edward A. Falk wrote:
> In article <78c5c8dc-88b7-4c98-a61b-babd1c798edf@googlegroups.com>,
> <pozzugno@gmail.com> wrote:
>> I have a simple (16-bit) embedded platform and I have to make the following calculations.
>>
>> unsigned int
>> func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) {
>> return (unsigned int)(pow((double)adc, exp) *
>> (double)pwr / pow((double)pt, exp));
>> }
>>
>> I noticed this calculation takes too much time, most probably for pow() function call
>> and double conversion.
>>
>> I'm finding a way to simplify/optimize this function. Consider that adc and pt
>> parameters are in the range 0..1023, exp is in the range 1.00-3.00, and pwr can be
>> 50-10000.

>
> Are you not worried about overflow?
>
> Your embedded processor almost certainly does not have a floating-point
> unit. This explains why your code is so slow.
>
> I see all values are guaranteed to be integer values.

The variable exp is double, and he didn't say that only integral values
of exp are allowed. If that is the case, he can speed up the code a lot
by using multiplications, rather than calls to pow().

Note: 'exp' is a bad name for a variable, given that it hides the
<math.h> function of the same name.

 BartC 04-22-2013 07:09 PM

Re: Optimizing pow() function

<pozzugno@gmail.com> wrote in message
> I have a simple (16-bit) embedded platform and I have to make the
> following calculations.
>
> unsigned int
> func(unsigned int adc, unsigned int pwr, unsigned int pt, double exp) {
> return (unsigned int)(pow((double)adc, exp) *
> (double)pwr / pow((double)pt, exp));
> }
>
> I noticed this calculation takes too much time, most probably for pow()
> function call and double conversion.
>
> I'm finding a way to simplify/optimize this function. Consider that adc
> and pt parameters are in the range 0..1023, exp is in the range 1.00-3.00,
> and pwr can be 50-10000.
>
> Any suggestion to avoid pow() function call?

Is there a version of pow() that uses float instead of double? That might be
a bit faster if floating point has to be done in software.

Can exp be anything from 1.00 to 3.00? How often will it be 1.0, 2.0, and
3.0? (These can be optimised.) Will it also only be specified to two
decimals? That suggests only 201 different values, although making use of a
200K lookup table indexed by adc/pt and 100*exp is probably not that
practical, and the results will be approximate.

Are the same adc/pt and exp combinations likely to recur frequently? It
might be possible to cache the results of the calculations (in a table a lot
smaller than 200K entries), but execution time might become non-linear. If
the combinations are predictable, then the table could be precalculated (it
all depends how this func() function is used).

--
Bartc

 James Kuyper 04-22-2013 07:35 PM

Re: Optimizing pow() function

On 04/22/2013 03:09 PM, BartC wrote:
....
> Is there a version of pow() that uses float instead of double? ...

C99 introduced powf(), which takes float arguments and returns a float
value.

 Malcolm McLean 04-22-2013 08:09 PM

Re: Optimizing pow() function

On Monday, April 22, 2013 8:09:31 PM UTC+1, Bart wrote:
> <pozzugno@gmail.com> wrote in message
>
>
> Can exp be anything from 1.00 to 3.00? How often will it be 1.0, 2.0, and
> 3.0? (These can be optimised.) Will it also only be specified to two
> decimals? That suggests only 201 different values, although making use of a
> 200K lookup table indexed by adc/pt and 100*exp is probably not that
> practical, and the results will be approximate.
>

pow(x, y) = exp(y * log(x)) for positive values.

the expensive part is working out log x. But if you can look it up, you need
far fewer than 200k entries.

--
You can read about how to implement the math library in my book Basic Algorithms
http://www.malcolmmclean.site11.com/www

 Keith Thompson 04-22-2013 09:24 PM

Re: Optimizing pow() function

James Kuyper <jameskuyper@verizon.net> writes:
> On 04/22/2013 03:09 PM, BartC wrote:
> ...
>> Is there a version of pow() that uses float instead of double? ...

>
> C99 introduced powf(), which takes float arguments and returns a float
> value.

But I wouldn't count on it being significantly faster than pow().

--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

 BartC 04-22-2013 09:27 PM

Re: Optimizing pow() function

"Keith Thompson" <kst-u@mib.org> wrote in message
news:lnsj2idzsi.fsf@nuthaus.mib.org...
> James Kuyper <jameskuyper@verizon.net> writes:
>> On 04/22/2013 03:09 PM, BartC wrote:
>> ...
>>> Is there a version of pow() that uses float instead of double? ...

>>
>> C99 introduced powf(), which takes float arguments and returns a float
>> value.

>
> But I wouldn't count on it being significantly faster than pow().

Not on a desktop PC with floating point hardware. But the OP is using a
'simple' 16-bit processor.

--
Bartc

All times are GMT. The time now is 10:54 PM.