# Calculate Y axis distance

Discussion in 'C Programming' started by David RF, May 5, 2012.

1. ### David RFGuest

Hi folks, first of all excuse my poor english, I have build this
function for calulate Y axis distance, I wan't to know if there is a
way to increase performance or improve the algorithm (dgra is called
many many times) Thanks.

#include <stdio.h>

double ddiv(double a, double b)
{
return b == 0.0 ? 0.0 : a / b;
}

double dgra(double d, int *n)
{
const double a[] = {1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0,
7.5, 8.0, 10.0, 12.5};
const double *pa = a;
double sign, product;

if (d == 0.0) {
if (n) *n = 0;
return 0.0;
}
d *= sign = (d > 0.0) ? 1.0 : -1.0; /* Store sign */
/* Trunc to most significant (by example 15678 turns into
1.5678) */
if (d < 1.0) {
for (product = 1.0; d < 1.00; product *= 0.10, d *=
10.0);
} else {
for (product = 1.0; d > 10.0; product *= 10.0, d *=
0.10);
}
d *= 1.1; /* Increase number 10% */
while (*pa < d) pa++; /* Search optimal value */
/* Must be divide by n numbers */
if (n) {
if (*pa == 1.5 || *pa == 3.0 || *pa == 6.0)
*n = 3; else
if (*pa == 2.0 || *pa == 4.0 || *pa == 8.0)
*n = 4; else
*n = 5;
}
return *pa * sign * product;
}

int main(void)
{
/* Test */
const double a[] = {112.8, -13.245, 121.5, 27894.0, 0.22452,
463.20, 7094.230, 235.20, 1420.04, 992312.52, 0.0};
const double *pa = a;
double d, f;
int n;

while (*pa) {
d = dgra(*pa, &n);
f = ddiv(d, n);
printf("%f = %f\n", *pa, d);
while (n >= 0) {
printf("\t%f\n", f * n);
n--;
}
pa++;
}
return 0;
}

--
David

David RF, May 5, 2012

2. ### Stefan RamGuest

David RF <> writes:
>I wan't to know if there is a
>way to increase performance

Yes: to measure the run-time of the application under the
target environment (of the customer) and then trying the
optimization techniques like: replacing double by float,
trying compiler-options (like -O3), using a
profiler/valgrind to analyze behavior (like cache misses,
KCacheGrind), loop unroling, cache-friendliness, inline
functions, strength reduction, reduction of register
pressure, writing in assembly, using »const«/»restrict« to
allow more optimizations.

Stefan Ram, May 5, 2012

3. ### Barry SchwarzGuest

On Sat, 5 May 2012 10:36:28 -0700 (PDT), David RF
<> wrote:

>Hi folks, first of all excuse my poor english, I have build this
>function for calulate Y axis distance, I wan't to know if there is a
>way to increase performance or improve the algorithm (dgra is called
>many many times) Thanks.

In the code you show, dgra is called only 10 times. Unless this is
only an example and you actually call it several thousand times, no
improvement is likely to have a noticeable affect.

>
>#include <stdio.h>
>
>double ddiv(double a, double b)
>{
> return b == 0.0 ? 0.0 : a / b;
>}

This function is unnecessary. See comment in main.

>
>double dgra(double d, int *n)
>{
> const double a[] = {1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0,
>7.5, 8.0, 10.0, 12.5};

If you make a static, it will not get reinitialized each time you call
dgra which will save some time.

> const double *pa = a;

Suggestion: If you change pa to an int (not const) and initialize it
to 0, you can save some time at the end of dgra. To do this, also add
an integer array parallel to a
static const int b[] = {5, 3, 4, 5, 3, 4, 5, 3, 5, 4, 5,5};

> double sign, product;
>
> if (d == 0.0) {
> if (n) *n = 0;
> return 0.0;
> }
> d *= sign = (d > 0.0) ? 1.0 : -1.0; /* Store sign */

Multiplication of doubles can be time consuming. The following may be
faster.
if (d > 0.0)
sign = 1.0;
else
{
sign = -1.0;
d = -d;
}

> /* Trunc to most significant (by example 15678 turns into
>1.5678) */

You should be aware that if d is 11.5, it will be represented exactly
but -

> if (d < 1.0) {
> for (product = 1.0; d < 1.00; product *= 0.10, d *=
>10.0);
> } else {
> for (product = 1.0; d > 10.0; product *= 10.0, d *=
>0.10);

after multiplying by .1, d will not equal 1.15 because that number
cannot be represented exactly.

> }
> d *= 1.1; /* Increase number 10% */
> while (*pa < d) pa++; /* Search optimal value */

Suggestion continued: All expressions in dgra of the form *pa need to
be changed to a[pa].

> /* Must be divide by n numbers */
> if (n) {
> if (*pa == 1.5 || *pa == 3.0 || *pa == 6.0)
> *n = 3; else
> if (*pa == 2.0 || *pa == 4.0 || *pa == 8.0)
> *n = 4; else
> *n = 5;
> }

Suggestion completed: This entire sequence can then be replace by
if (n)
*n = b[pa];

> return *pa * sign * product;
>}
>
>int main(void)
>{
> /* Test */
> const double a[] = {112.8, -13.245, 121.5, 27894.0, 0.22452,
>463.20, 7094.230, 235.20, 1420.04, 992312.52, 0.0};
> const double *pa = a;
> double d, f;
> int n;
>
> while (*pa) {
> d = dgra(*pa, &n);
> f = ddiv(d, n);

You could replace the call to ddiv with the same one statement that
ddiv contains, just change the variable names. This will eliminate
f = (n == 0.0 ? 0.0 : d/n);

> printf("%f = %f\n", *pa, d);
> while (n >= 0) {
> printf("\t%f\n", f * n);
> n--;
> }
> pa++;
> }
> return 0;
>}

--
Remove del for email

Barry Schwarz, May 5, 2012
4. ### Ian CollinsGuest

On 05/ 6/12 07:51 AM, Barry Schwarz wrote:
> On Sat, 5 May 2012 10:36:28 -0700 (PDT), David RF
> <> wrote:
>
>> Hi folks, first of all excuse my poor english, I have build this
>> function for calulate Y axis distance, I wan't to know if there is a
>> way to increase performance or improve the algorithm (dgra is called
>> many many times) Thanks.
>>
>> #include<stdio.h>
>>
>> double ddiv(double a, double b)
>> {
>> return b == 0.0 ? 0.0 : a / b;
>> }

>
> This function is unnecessary. See comment in main.

<snip>

>> int main(void)
>> {
>> /* Test */
>> const double a[] = {112.8, -13.245, 121.5, 27894.0, 0.22452,
>> 463.20, 7094.230, 235.20, 1420.04, 992312.52, 0.0};
>> const double *pa = a;
>> double d, f;
>> int n;
>>
>> while (*pa) {
>> d = dgra(*pa,&n);
>> f = ddiv(d, n);

>
> You could replace the call to ddiv with the same one statement that
> ddiv contains, just change the variable names. This will eliminate
> the overhead calling the function.

Any compiler worth using will do that for you. All you loose by
removing the function is clarity - assuming the function name is meaningful!

--
Ian Collins

Ian Collins, May 6, 2012
5. ### David RFGuest

On 5 mayo, 21:51, Barry Schwarz <> wrote:
> On Sat, 5 May 2012 10:36:28 -0700 (PDT), David RF
>
> <> wrote:
> >Hi folks, first of all excuse my poor english, I have build this
> >function for calulate Y axis distance, I wan't to know if there is a
> >way to increase performance or improve the algorithm (dgra is called
> >many many times) Thanks.

>
> In the code you show, dgra is called only 10 times.  Unless this is
> only an example and you actually call it several thousand times, no
> improvement is likely to have a noticeable affect.
>
>
>
> >#include <stdio.h>

>
> >double ddiv(double a, double b)
> >{
> >        return b == 0.0 ? 0.0 : a / b;
> >}

>
> This function is unnecessary.  See comment in main.
>
>
>
> >double dgra(double d, int *n)
> >{
> >        const double a[] = {1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0,
> >7.5, 8.0, 10.0, 12.5};

>
> If you make a static, it will not get reinitialized each time you call
> dgra which will save some time.
>
> >        const double *pa = a;

>
> Suggestion: If you change pa to an int (not const) and initialize it
> to 0, you can save some time at the end of dgra.  To do this, also add
> an integer array parallel to a
>     static const int b[] = {5, 3, 4, 5, 3, 4, 5, 3, 5, 4, 5,5};
>
> >        double sign, product;

>
> >        if (d == 0.0) {
> >                if (n) *n = 0;
> >                return 0.0;
> >        }
> >        d *= sign = (d > 0.0) ? 1.0 : -1.0; /* Store sign */

>
> Multiplication of doubles can be time consuming.  The following may be
> faster.
>      if (d > 0.0)
>           sign = 1.0;
>      else
>           {
>           sign = -1.0;
>           d = -d;
>           }
>
> >        /* Trunc to most significant (by example 15678 turns into
> >1.5678) */

>
> You should be aware that if d is 11.5, it will be represented exactly
> but -
>
> >        if (d < 1.0) {
> >                for (product = 1.0; d < 1.00; product *= 0.10, d *=
> >10.0);
> >        } else {
> >                for (product = 1.0; d > 10.0; product *= 10.0, d *=
> >0.10);

>
> after multiplying by .1, d will not equal 1.15 because that number
> cannot be represented exactly.
>
> >        }
> >        d *= 1.1; /* Increase number 10% */
> >        while (*pa < d) pa++; /* Search optimal value */

>
> Suggestion continued: All expressions in dgra of the form *pa need to
> be changed to a[pa].
>
> >        /* Must be divide by n numbers */
> >        if (n) {
> >                if (*pa == 1.5 || *pa == 3.0 || *pa == 6.0)
> >                        *n = 3; else
> >                if (*pa == 2.0 || *pa == 4.0 || *pa == 8.0)
> >                        *n = 4; else
> >                        *n = 5;
> >        }

>
> Suggestion completed: This entire sequence can then be replace by
>      if (n)
>          *n = b[pa];
>
> >        return *pa * sign * product;
> >}

>
> >int main(void)
> >{
> >        /* Test */
> >        const double a[] = {112.8, -13.245, 121.5, 27894.0, 0.22452,
> >463.20, 7094.230, 235.20, 1420.04, 992312.52, 0.0};
> >        const double *pa = a;
> >        double d, f;
> >        int n;

>
> >        while (*pa) {
> >                d = dgra(*pa, &n);
> >                f = ddiv(d, n);

>
> You could replace the call to ddiv with the same one statement that
> ddiv contains, just change the variable names.  This will eliminate
> the overhead calling the function.
>                f = (n == 0.0 ? 0.0 : d/n);
>
> >                printf("%f = %f\n", *pa, d);
> >                while (n >= 0) {
> >                        printf("\t%f\n", f * n);
> >                        n--;
> >                }
> >                pa++;
> >        }
> >        return 0;
> >}

>

Thanks Barry

David RF, May 6, 2012
6. ### BartCGuest

"David RF" <> wrote in message
news:...

> const double a[] = {1.25, 1.5, 2.0, 2.5, 3.0, 4.0, 5.0, 6.0,
> 7.5, 8.0, 10.0, 12.5};

> if (*pa == 1.5 || *pa == 3.0 || *pa == 6.0)
> *n = 3; else
> if (*pa == 2.0 || *pa == 4.0 || *pa == 8.0)
> *n = 4; else
> *n = 5;

pa always points into the a[] array, and the contents of a[] are fixed? Then
it might be better to use an index into the array, and use tests such as:

if (index==1 || index==4 || index==6)

etc.

> while (*pa) {
> d = dgra(*pa, &n);
> f = ddiv(d, n);
> printf("%f = %f\n", *pa, d);
> while (n >= 0) {
> printf("\t%f\n", f * n);
> n--;
> }
> pa++;
> }

Comment out the printf() statements, wrap a loop around it to execute it at
least a million times (remember to re-initialise pa each time), and find
some way of timing the code. Then it will be easy to try different things
and see if they make a difference. Reinstate the printf() statements every
so often (and disable the outer loop) to check the output is still right.

--
Bartc

BartC, May 6, 2012