繁体   English   中英

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

[英]Can floating point multiplication by zero be optimised at runtime?

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

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

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

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

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

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

除非计算是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);
}

如果要优化代码,则必须自行测试零。 编译器不会为您执行此操作。

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

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

  • DetOf2x2(...)可能有副作用(如输出到日志文件),即使currentElement0也需要发生这种副作用,
  • DetOf2x2(...)可以返回值,无论如何都应传播到term1的非数字/ NaN标记(如Nils Pipenbrinck首先提到的那样)

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

如果你想避免调用Detof2x2(...) ,请尝试:

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

现代的CPU会比实际的分支处理乘法由零速度非常快,快于一般的乘法,并迅速。 甚至不打算尝试优化它,除非零将通过至少几十个指令传播。

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

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

#其他

return currentElement * det(M);

#万一

}

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM