可以在运行时优化浮点乘以零吗?

时间:2013-03-05 02:15:58

标签: c++ c optimization floating-point multiplication

我正在编写一个算法来查找nxn矩阵的逆矩阵。让我们来看一个3x3矩阵的具体情况。

当您手动反转矩阵时,通常会查找包含一个或多个零的行/列,以便更快地执行行列式计算,因为它会消除您需要计算的项。

在C / C ++中遵循此逻辑,如果您标识具有一个或多个零的行/列,您将最终得到以下代码:

float term1 = currentElement * DetOf2x2(...);
//           ^
//           This is equal to 0.
//
// float term2 = ... and so on.

由于编译器无法知道currentElement在编译时将为零,因此无法将其优化为float term = 0;,因此浮点乘法将在运行时执行。

我的问题是,这些零值是否会使浮点乘法更快,或者无论currentElement的值如何,乘法都会花费相同的时间?如果在运行时无法优化乘法,那么我可以删除搜索包含零的行/列的逻辑。

5 个答案:

答案 0 :(得分:7)

除非计算是trival(例如所有常量),否则不允许编译器对此进行优化。

原因是,DetOf2x2可能返回NAN浮点值。将NAN与零相乘不会返回零,而是再次返回NAN。

您可以在此处使用此小测试自己尝试:

int main (int argc, char **args)
{
  // generate a NAN
  float a = sqrt (-1);

  // Multiply NAN with zero..
  float b = 0*a;

  // this should *not* output zero
  printf ("%f\n", b);
}

如果要优化代码,则必须自行测试零。编译器不会为你做那件事。

答案 1 :(得分:6)

float term1 = currentElement * DetOf2x2(...);

即使currentElement为0,编译器也会调用DetOf2x2(...):这肯定比最终的乘法要贵得多,无论是否为0。原因有很多:

  • DetOf2x2(...)可能会产生副作用(例如输出到日志文件),即使currentElement0,也可能会发生
  • DetOf2x2(...)可能会返回非传播号码/ NaN标记的值,无论如何都会传播到term1(如Nils Pipenbrinck首先所述)

鉴于DetOf2x2(...)几乎肯定会处理只能在运行时确定的值,后一种可能性不能在编译时排除。

如果您想避免拨打Detof2x2(...),请尝试:

float term1 = (currentElement != 0) ? currentElement * DetOf2x2(...) : 0;

答案 2 :(得分:2)

现代CPU实际上会比一般的乘法更快,更快地处理乘数非常,并且比分支更快地很多。甚至不打算尝试优化它,除非零将通过至少几十个指令传播。

答案 3 :(得分:0)

在运行时执行的优化称为JIT(即时)优化。在翻译(编译)时执行的优化称为AOT(提前)优化。你指的是JIT优化。编译器可能会在您的机器代码中引入JIT优化,但它实现的优化要比常见的AOT优化要复杂得多。优化通常基于重要性来实现,并且这种“优化”可能被视为负面地影响其他算法。 C实现不需要执行任何这些优化。

您可以手动提供优化,这将是“搜索包含零的行/列的逻辑”,或者类似这样的内容:float term1 = currentElement != 0 ? currentElement * DetOf2x2(...) : 0;

答案 4 :(得分:0)

以下构造在编译时可以猜出" currentElement"的值。

float term1 = currentElement? currentElement * DetOf2x2(...):0;

如果在编译时无法猜到,它将在运行时进行检查,性能取决于处理器体系结构:分支之间的权衡(包括分支延迟和重建指令管道的延迟可能会增加到10或20个周期)和平坦代码(一些处理器每个周期运行3个指令)和硬件分支预测(当硬件支持分支预测时)。

由于x86_64处理器上的乘法吞吐量接近1个周期,因此根据操作数值(如0.0,1.0,2.0或12345678.99)不存在性能差异。如果存在这样的差异,那将被视为加密风格软件中的隐蔽通道。

GCC允许在编译时检查函数参数

内联浮动myFn(float currentElement,myMatrix M)

{

#if __builtin_constant_p(currentElement)&& currentElement == 0.0

返回0.0;

的#else

return currentElement * det(M);

#ENDIF

}

您需要在编译器中启用内联和过程间优化。