我正在编写一个代码,其中优化是一个真正的问题,我真的需要尽快运行这段代码。
所以我有类似的事情:
a是double,x是int。 在我的具体情况下,x总是2或3
double c1[3] = {5345.4364654, 43346.6876978, 1224324.654756};
double c2[3] = {49876.642543678, 1104.57576756};
...
..
if (x>2)
a = c1[0]*x*x*x-c1[1]*x*x+c1[2]*x;
else
a = c2[0]*x*x+c2[1]*x;
我想知道如果删除if..else并执行类似
之类的操作会更快double c [2][3] = {
{5345.4364654, 43346.6876978 , 1224324.654756},
{0 ,49876.642543678, 1104.575767561}
};
a = c1[x-2][0]*x*x*x-c1[x-2][1]*x*x+c1[x-2][2]*x;
它告诉我,如果将乘以零被视为"特殊情况"那么第二个代码将运行得更快由编译器,但我不确定
如果你们有任何人有想法请帮助:) 非常感谢
答案 0 :(得分:2)
我实际上是用你的第一张表格,但试着让它变得更容易。
a是double,x是int。在我的具体情况下,x总是0或1,但我不能将它作为布尔值(true / false),它基于int!
我们可以做很多事情,因为我们知道它只能是0或1。
我们可以摆脱整个c2
的情况,因为乘以0总是会导致0。
如果x
为1乘以x,则不会改变任何内容。将y
乘以1始终返回y。
现在我们得到类似的东西:
double c1[3] = {5345.4364654, 43346.6876978, 1224324.654756};
a = (c1[0]-c1[1]+c1[2]) * x;
答案 1 :(得分:2)
现在乘法非常快,所以避免分支可能比将一个乘法跳过0更重要。
我将下面的等式分解为:
double c [2][3] = {
{5345.4364654, 43346.6876978 , 1224324.654756},
{0 ,49876.642543678, 1104.575767561}
};
a = ((c1[x-2][0]*x-c1[x-2][1])*x+c1[x-2][2])*x;
注意,如果数组c
确实是一个编译时常量(如果你通过使它成为const来帮助编译器),你可能会提示编译器预先计算x = 2和x的值= 3喜欢这样:
switch (x)
{
case 2:
a = ((c1[x-2][0]*x-c1[x-2][1])*x+c1[x-2][2])*x;
break;
case 3:
a = ((c1[x-2][0]*x-c1[x-2][1])*x+c1[x-2][2])*x;
break;
default:
// this should never happen
}
这可能会使编译器直接编译答案。
这很可能也可以起作用:
switch (x)
{
case 2:
case 3:
a = ((c1[x-2][0]*x-c1[x-2][1])*x+c1[x-2][2])*x;
break;
default:
// this should never happen
}
但是,如果c
确实是一个编译时常量且x
实际上是2或3,那么你只有两个输入和两个结果,所以你可能只计算出计算器上的两个答案如果你真的担心速度,可以在switch语句中对它们进行硬编码。
答案 2 :(得分:1)
如果x
完全等于0
,那么a
也是0
,它只是一个多项式。如果你真的想要,你可以做一个额外的案例
else if (x == 0)
a = 0;
但是你很可能看不到速度的可观察性增加。这闻起来像是不必要的微观优化。
答案 3 :(得分:1)
避免跳转通常对性能有好处,因为每次条件跳转都会干扰CPU管道。最好做一些额外的(易于并行化的)线性计算。
答案 4 :(得分:1)
您可以提前预先计算一些值。 给定
a = c1 [x-2] [0] * x * x * x-c1 [x-2] [1] * x * x + c1 [x-2] [2] * x;
表达式x-2
使用了3次。
如果x为2或3,则应将它们插入等式并简化:
switch (x)
{
case 2:
a = c1[0][0]*8 - c1[0][1] * 4 + c1[0][2]* 2;
break;
case 3:
a = c1[1][0]*27 - c1[1][1] * 9 + c1[1][2] * 3;
break;
}
虽然您可以先获得更多性能,然后再添加:
const double term1 = c1[x-2][0]*x*x*x;
const double term2 = c1[x-2][1]*x*x;
const double term3 = c1[x-2][2]*x;
a = term1 + term2 + term;
将上面的内容与一些预取相结合,可能会获得更好的性能:
// Prefetch
const double v0 = c1[x-2][0];
const double v1 = c1[x-2][1];
const double v2 = c1[x-2][2];
// Mulitply
const double t1 = v0 * x * x * x;
const double t2 = v1 * x * x;
const double t3 = v2 * x;
// Sum
a = t1 + t2 + t3;
最好的方法是编写代码并查看汇编语言。
也不是const
的使用。 const
的使用将有助于编译器执行更好的优化。