Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/142.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 浮点乘零能否在运行时得到优化?_C++_C_Optimization_Floating Point_Multiplication - Fatal编程技术网

C++ 浮点乘零能否在运行时得到优化?

C++ 浮点乘零能否在运行时得到优化?,c++,c,optimization,floating-point,multiplication,C++,C,Optimization,Floating Point,Multiplication,我正在写一个算法来求nxn矩阵的逆。让我们以3x3矩阵为例 手动反转矩阵时,通常会查找包含一个或多个零的行/列,以加快行列式计算,因为它消除了需要计算的项 按照C/C++中的此逻辑,如果您用一个或多个零标识行/列,则最终将得到以下代码: float term1 = currentElement * DetOf2x2(...); // ^ // This is equal to 0. // // float term2 = ... and so on. 由

我正在写一个算法来求nxn矩阵的逆。让我们以3x3矩阵为例

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

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

float term1 = currentElement * DetOf2x2(...);
//           ^
//           This is equal to 0.
//
// float term2 = ... and so on.
由于编译器无法知道
currentElement
在编译时将为零,因此无法将其优化为
float term=0

我的问题是,这些零值会使浮点乘法更快,还是不管
currentElement
的值是多少,乘法所用的时间都相同?如果无法在运行时优化乘法,那么我可以删除搜索包含零的行/列的逻辑。

现代CPU将非常快速地处理乘零运算,比一般乘法运算更快,比分支运算更快。除非零将通过至少几十条指令传播,否则不要费心去优化它。

编译器不允许优化它,除非计算很繁琐(例如,所有常量)

原因是,Deto2x2可能返回一个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);
}

如果你想优化你的代码,你必须自己测试零。编译器不会为您这样做。

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

您可以手动提供优化,即“搜索包含零的行/列的逻辑”,或类似的内容:
float term1=currentElement!=0 ? currentElement*Deto2x2(…):0

float term1 = currentElement * DetOf2x2(...);
即使currentElement为0,编译器也将调用
deto2x2(…)
:这肯定比最终乘法的成本要高得多,不管是否为0。原因有多种:

  • deto2x2(…)
    可能会产生副作用(如输出到日志文件),即使
    currentElement
    0
    ,也会产生副作用,并且
  • deto2x2(…)
    可能返回像Not-a-Number/NaN哨兵这样的值,无论如何都应该传播到
    term1
    (如Nils Pipenbrick首先指出的)
鉴于
deto2x2(…)
几乎肯定是在处理只能在运行时确定的值,在编译时不能排除后一种可能性

如果要避免调用
deto2x2(…)
,请尝试:

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

当编译器可以猜测“currentElement”的值时,以下构造在编译时有效

float term1=currentElement?currentElement*Deto2x2(…):0

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

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

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

内联浮点myFn(浮点currentElement,myMatrix M)

{

#如果内置常数p(currentElement)&¤tElement==0.0

返回0.0

#否则

返回电流元件*det(M)

#恩迪夫

}


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

取决于FPU设计。有些会更快,有些不会。为什么不做一个测试看看呢?但是零会通过相当多的指令传播,正确预测的分支会以零周期执行,而乘法在一般情况下可能会以一对二执行。关于定性的“多”,假设
deto2x2
只包含正常的1/(ad bc),那么多个浮点指令是否仍然比分支更快?或者系统实现是独立的?目前,我很难找到FP乘零的硬件优化源-这可能只适用于标量整数指令。无论如何,2x2行列式几乎肯定是太小的计算,不值得跳过一个分支。例如,Intel的Sandy Bridge可以在同一个时钟周期内完成独立的FP向量乘法、加法和洗牌,因此您可能可以将3个2x2行列式的计算流水线化到一个只需要十几个周期的指令序列中。我建议将3x3行列式作为一个函数来实现。还有一些硬件优化。他好像在问ALU的等级。可以说,C++实现不执行JIT优化,除非是R。