重新排列等式

时间:2013-10-13 22:02:34

标签: c performance math optimization floating-point

我的C代码中有以下等式

k * dl * (1.0 + pHold / centre
       + (pHold * pHold) / (2.0 * centre * centre)
       - square / (2.0 * centre))

我知道浮点除法比乘法要贵得多,而且我已经和它搏斗了一段时间。有没有办法重新排列这个以划分一个部门?

由于

7 个答案:

答案 0 :(得分:7)

请注意,在您实际尝试优化部分之前,您应该:
  • 确保正确
  • 确保如何在更高级别优化此功能 〜我的程序调用此计算的次数是否超过实际需要的次数?
    我可以使用之前的结果吗? What is dynamic programming?
  • 一旦你知道瓶颈在哪里, 基准测试 应该遵循:
    似乎很慢......它有多“慢”? ......它应该如何“快速”?

但是如果你确定方程本身应该被优化,你可以使用centre的乘法逆在你的等式中出现4次这一事实,将除法计数减少到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);

另请注意,这些更改实际上可能会影响此等式的结果,因此如果您决定更改它,请确保它仍能产生所需的输出。

答案 1 :(得分:4)

如果你看看分数的分母,你可以看到,制作一个共同面额将允许你只进行一次除法(以更多的乘法为代价):

k * dl * (1.0
  + pHold                  / (centre)
  - square                 / (2.0 * centre)
  + (pHold * pHold)        / (2.0 * centre * centre)
)

如果您确定浮点乘法优于浮点除法,那么:

k * dl * (1.0
  + (pHold * 2.0 * centre) / (2.0 * centre * centre)
  - (square * centre)      / (2.0 * centre * centre)
  + (pHold * pHold)        / (2.0 * centre * centre)
)

哪个成为:

k * dl * (1.0
  + ( (pHold * 2.0 * centre)
    - (square * centre)
    + (pHold * pHold) )     / (2.0 * centre * centre)
)

答案 2 :(得分:1)

代数地,您可以将其缩减为单个分区。使用:

    {li> k k {li> d dl {li> p pHold {li> c centre {li> s square

你的等式是:

           p     p.p     s
k.d ( 1 + --- + ----- - --- )
           c    2.c.c   2.c

转换为:

k.d ( 2.c.c + 2.c.p + p.p - c.s )
---------------------------------
             2.c.c

因此

k.d (2.c (c + p) - c.s + p.p)
-----------------------------
            2.c.c

或者,就原始变量而言:

(k * dl * (2 * centre * (centre + pHold) - centre * square + pHold * pHold)) /
                    (2 * centre * centre)

这是否与原始方程在数值上是一个单独的讨论。为了讨论这个问题,我们需要知道方程中每个项的典型范围(即使这样,我的大脑也会受到伤害)。

答案 3 :(得分:0)

你可以删除至少一个:

k * dl * (1.0 + (pHold
       + (pHold * pHold) / (2.0 * centre)
       - square * 0.5) / centre)

答案 4 :(得分:0)

在过去,你可能会写

oocenter = 1/center; 

并在表达式

中使用它
k * dl * (1.0 + pHold * oocentre
       + pHold * pHold * 0.5 * oocentre * oocentre
       - square * 0.5 * oocentre)

如今,我相信编译器足够聪明,可以为您做到这一点。我建议努力实现矢量化和并行化。

答案 5 :(得分:0)

嗨,我不知道编程C:)

但是考虑到k,dl,pHold,center和square都是变量,你可以将这个数学方程简化为:

  k*dl*(2.0* centre * centre + 2.0 * centre * pHold - centre *square + pHold * pHold)
  /  (2.0 * centre * centre)

将变量替换为单个字符变量并使用http://www.wolframalpha.com

编辑:Nikos C基本上有相同的答案,但是考虑了2c。您可以测试/选择哪一个表现更好。

答案 6 :(得分:0)

您可以将此减少到只有一个部门:

k * dl * (2 * centre * (centre + pHold) + pHold * pHold - centre * square)
/ (2.0 * centre * centre)