繁体   English   中英

使用速记IF的C ++编译器优化

[英]C++ compiler optimization with shorthand IF

我在考虑关于精简if / else时优化编译器的问题。

我有这个功能:

double eu_distance (const coor& x, const coor& y) {

return ((y.x - x.x)*(y.x - x.x) + (y.y - x.y)*(y.y - x.y));
}

我想知道什么更有效?

min = min > eucl_distance(point_a, point_b) ? eucl_distance(point_a, point_b) : min;

要么

double dis = eucl_distance(point_a, point_b);
if (min > dis)
    min = dis;

在前一种情况下,编译器(在我的情况下为GCC 4.6.2)是否知道如何优化if / else以保持eucl_distance()的返回值可重复使用,而不是对其进行两次计算?

背负式问题是:

有什么更有效的?

(y.x - x.x)*(y.x - x.x)

要么

pow((y.x - x.x),2)

PS:对不起,我不能选择多个正确答案! :(谢谢大家的回答!我非常感谢他们!!

没有一个统一的答案:您必须分析实现所生成的代码才能确定。 但是,在大多数情况下,如果eu_distance位于单独的转换单元中,并且没有特别注释,则编译器将无法知道使用相同的参数两次调用将产生相同的结果。 在这种情况下,第二种形式肯定会更快。 另一方面,如果可以内嵌eu_distance ,则任何体面的优化器最终都会为两者生成几乎完全相同的代码。

实际上,我几乎可以肯定会使用第三种形式:

min = std::min( eu_distance( point_a, point_b ), min );

(我假设eucl_distance是一个错字eu_distance 。)

另外,我会避免使用诸如min类的名称。 有人很可能会添加using namespace std; 之后,甚至包括<windows.h> ,而无需定义NOMINMAX (如果NOMINMAX <windows.h>会将minmax定义为宏。如果您定义自己的minmax甚至包括<algorithm>这都会导致一些有趣的错误消息。)

关于pow( x, 2 ) :同样,您实际上必须进行测量,但是通常,即使x是一个复杂的表达式, x * x也会更快。 (当然,如果表达式不是平凡的,那么认识两个x可能并不那么容易,这会使代码更难阅读。在这种情况下,您可能需要考虑一个小函数,例如squared ,除了返回x * x什么都没有。如果对性能有所影响,请对其进行内联。)

在许多变量可能影响优化器的意义上,所有关于优化器如何对待代码的问题都很难解决 答案的第一部分是,在任何情况下,缓存函数的结果并重用它都不会比其他方法差,因此,我将继续使用第二种方法。

从第一种方法可以优化的内容来看,这取决于代码的布局方式。 如果编译器可以访问euclid_distance的定义euclid_distance 该定义,则它可以有效地确定该函数是函数,并且在第二个调用中将产生相同的输出,因此它可能会缓存第一个调用的值。 如果编译器无法访问该函数的定义,则它无法知道对该函数的第一次调用和第二次调用是否会产生相同的结果(考虑rand() ,每个调用会产生不同的数字),因此它将调用函数两次。 您可以通过在编译器的提示中标记函数来帮助您。 您可以在gcc中的__pure属性上进行Google搜索,如果我没有__pure话,它将在这种情况下对优化器有所帮助。

同样,关于pow与普通乘法的使用,对于2的幂,我只会使用直接乘法。 pow基本上不可能使其更有效率。 在这种情况下,您不需要缓存yx-xx因为编译器会发现它已被重用并且可以为您完成。

好吧,从理论上讲:

double dis = eucl_distance(point_a, point_b);
if (min > dis)
    min = dis;

比这更有效:

min = min > eucl_distance(point_a, point_b) ? eucl_distance(point_a, point_b) : min;

...只是因为您消除了一个额外的调用eucl_distance(point_a, point_b)

但是,如果将函数标记为“纯”,或者如果编译器可以看到该定义并确定它是纯净的,则它将消除对它的额外调用,就像它消除了重复的数学表达式一样,然后生成的代码几乎相同。 但是,您不能总是去检查组装等,因此我坚持使用第一种情况,这种情况更清洁。

至于您的piggy带问题, (yx - xx)*(yx - xx)更快(您可以更具体一些,并将y - x结果存储在tmp变量中)...但是,编译器非常清楚pow函数,因为第二个参数是编译时表达式,它可以轻松地展开该代码以匹配您的手动编码乘法。 但是同样,您不能真正依靠您,因此,如果您可以使代码更清晰,更明显,请执行此操作。 我看不出您为什么要致电pow(something, 2)任何原因。

永远记住,过早的优化是不好的。 但是,仍然不要一开始就编写糟糕的慢速代码:)

我会说:

  • 不要假设任何编译器行为。
  • 重用结果以避免不必要的调用

没有任何东西告诉编译器您的eucl_distance函数完全是幂等的,因此假设缓存结果,它几乎没有机会跳过额外的调用。 (如果您在调用中增加了静态计数器变量,该怎么办呢?)

对于乘法与pow的事情,我猜是取决于底层处理器的数学优化。

暂无
暂无

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

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