Reputation: 109
I have the following equation in my C code
k * dl * (1.0 + pHold / centre
+ (pHold * pHold) / (2.0 * centre * centre)
- square / (2.0 * centre))
I know that floating point divisions are a lot more expensive than multiplications, and I have been wrestling with this for a while. Is there any way to rearrange this to cut out a division?
Thanks
Upvotes: 1
Views: 377
Reputation: 42133
Just note that before you actually try to optimize some part, you should:
But in case you are sure that the equation itself should be optimized, you could use the fact that the multiplicative inverse of centre
appears in your equation 4 times, reducing the count of divisions to 1:
double centreInv = 1.0 / centre;
double pHoldToCentre = pHold * centreInv;
double result =
k * dl * (1.0 + pHoldToCentre
+ 0.5 * pHoldToCentre * pHoldToCentre
- 0.5 * square * centreInv);
Also note that these kind of changes might actually affect the result of this equation, so if you decide to change it, make sure it still produces desired output.
Upvotes: 7
Reputation: 754800
Algebraically, you can reduce it to a single division. Using:
k
for k
d
for dl
p
for pHold
c
for centre
s
for square
your equation is:
p p.p s
k.d ( 1 + --- + ----- - --- )
c 2.c.c 2.c
which transforms to:
k.d ( 2.c.c + 2.c.p + p.p - c.s )
---------------------------------
2.c.c
and hence to
k.d (2.c (c + p) - c.s + p.p)
-----------------------------
2.c.c
Or, in terms of your original variables:
(k * dl * (2 * centre * (centre + pHold) - centre * square + pHold * pHold)) /
(2 * centre * centre)
Whether that is as good numerically as the original equation is a separate discussion. To discuss that, we'd need to know the typical ranges for each of the terms in the equation (and even then, my brain would hurt).
Upvotes: 1
Reputation: 608
Hi I have no Idea of Programming C :)
But given k, dl, pHold, centre and square are all variables, you can simplify this mathematical equation to:
k*dl*(2.0* centre * centre + 2.0 * centre * pHold - centre *square + pHold * pHold)
/ (2.0 * centre * centre)
substitute variables to single character variables and use http://www.wolframalpha.com
edit: Nikos C has basically the same answer but is factoring out 2c. You can test/chose which one performs better.
Upvotes: 0
Reputation: 9643
If you look at the denominators for the fractions you can see that making a common denomination would allow you to do the division just once (at the expense of more multiplications):
k * dl * (1.0
+ pHold / (centre)
- square / (2.0 * centre)
+ (pHold * pHold) / (2.0 * centre * centre)
)
If you are sure that a floating point multiplication is better than a floating point division then:
k * dl * (1.0
+ (pHold * 2.0 * centre) / (2.0 * centre * centre)
- (square * centre) / (2.0 * centre * centre)
+ (pHold * pHold) / (2.0 * centre * centre)
)
Which becomes:
k * dl * (1.0
+ ( (pHold * 2.0 * centre)
- (square * centre)
+ (pHold * pHold) ) / (2.0 * centre * centre)
)
Upvotes: 4
Reputation: 51910
You can reduce this to only one division overall:
k * dl * (2 * centre * (centre + pHold) + pHold * pHold - centre * square)
/ (2.0 * centre * centre)
Upvotes: 0
Reputation: 59290
In the old days, you probably would have written
oocenter = 1/center;
and used it in the expression
k * dl * (1.0 + pHold * oocentre
+ pHold * pHold * 0.5 * oocentre * oocentre
- square * 0.5 * oocentre)
Nowadays, I believe the compilers are smart enough to do that for you. I would suggest working towards vectorization and parallelization.
Upvotes: 0
Reputation: 239301
You cn cut out at least one:
k * dl * (1.0 + (pHold
+ (pHold * pHold) / (2.0 * centre)
- square * 0.5) / centre)
Upvotes: 0