1

我的 C 代码中有以下等式

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

我知道浮点除法比乘法要昂贵得多,我已经为此苦苦挣扎了一段时间。有没有办法重新安排这个以减少一个部门?

谢谢

4

7 回答 7

7
请注意,在您实际尝试优化某些部分之前,您应该:
  • 确保它是正确的
  • 确保没有办法在更高级别上优化它
    ~我的程序调用这个计算的次数不是比实际需要的多吗?
    ~我可以使用以前的结果吗?什么是动态规划?
  • 一旦你知道瓶颈在哪里,基准测试应该遵循:
    它似乎很慢......它有多“慢”?...它应该变得多“快”?

但是,如果您确定方程本身应该被优化,您可以使用乘法倒数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);

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

于 2013-10-13T22:16:56.803 回答
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)
)
于 2013-10-13T22:23:22.300 回答
1

在代数上,您可以将其简化为一个除法。使用:

  • k为了k
  • d为了dl
  • p为了pHold
  • c为了centre
  • 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)

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

于 2013-10-13T22:33:15.860 回答
0

在过去,你可能会写

oocenter = 1/center; 

并在表达式中使用它

k * dl * (1.0 + pHold * oocentre
       + pHold * pHold * 0.5 * oocentre * oocentre
       - square * 0.5 * oocentre)

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

于 2013-10-13T22:20:05.300 回答
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。您可以测试/选择哪一个表现更好。

于 2013-10-13T22:21:32.583 回答
0

您可以将其减少到总体上只有一个部门:

k * dl * (2 * centre * (centre + pHold) + pHold * pHold - centre * square)
/ (2.0 * centre * centre)
于 2013-10-13T22:21:48.960 回答
0

你至少删掉了一个:

k * dl * (1.0 + (pHold
       + (pHold * pHold) / (2.0 * centre)
       - square * 0.5) / centre)
于 2013-10-13T22:17:33.150 回答