【问题标题】:Should I avoid operations between constants in a loop?我应该避免循环中常量之间的操作吗?
【发布时间】:2018-10-02 23:05:11
【问题描述】:

我想知道在 c++ 中是否有某种优化或缓存可以防止重复常量之间的相同数学运算,尤其是在循环中,从而降低应用程序性能。 例如:

    

for (int i = 0; i <= 100; i ++)
    std::cout << i << "meters / s:" << "=" << i * (3600/1000) << "Km / h" << endl;

上面的例子显然是虚构的,但这只是为了说明情况。它可能是一百万次循环,包含数百次涉及重复常数的计算。

那我问:

 

  1. “(3600/1000)”计算是否会重复运行 100 次循环?
  2. 这样,为了避免性能损失,我是否应该在循环之前将此计算存储在一个常量变量中并通过该变量更改计算?
  3. 或者我不必担心,因为 c++ 提供了一种自动优化这些情况以避免性能损失的方法?
  4. 或者即使我将 3600 更改为常数“a”,将 1000 更改为常数“b”,也就是说,即使“a”和“b”是常数,我也不会使用 3600/1000,而是使用“a / b”,但是操作是重复计算100次还是有什么优化?

我知道这个问题很中肯,因为它涉及到应该采用的编程风格。

【问题讨论】:

  • 这取决于你的编译器。大多数现代编译器会将其优化为常量。
  • 你真的不需要担心。编译器足够聪明,可以在编译时将3600/1000 替换为360
  • C++ 明确允许编译器实现任何没有可观察到的效果的优化。执行您概述的优化没有可观察到的效果,因此这是允许的。 C++标准不要求编译器实现这种优化,只允许;但实际上所有现代 C++ 编译器都会这样做,尤其是当它只涉及常量时。
  • 几乎所有编译器都会优化掉文字计算。顺便说一句,像你这样的小循环(0到100)你担心不必要的优化
  • 我猜你的意思是 3.6 但是.. 在我看来它会导致 3 代替? int 的 3600 / int 的 1000 看起来像 3。如果您没有为新生处理器使用非常有趣的所谓研究编译器,那么您提到的任何一个都应该导致编译时间常数计算。

标签: c++ performance caching optimization constants


【解决方案1】:

这读起来像评论,但与您担心的答案非常相关。

编译器比你聪明。

在尝试编写快速代码时,这是一个非常好的经验法则。

编写可读的代码,您的编译器很可能会完成剩下的工作。

【讨论】:

    【解决方案2】:

    不用担心您显示的 sn-p。常量折叠是一种基本的优化技术。循环展开也是如此(尤其是在迭代次数固定的情况下)。

    您唯一需要的是激活优化的编译器标志:clang/GCC 上的 -O3(或其他),MSVC 上的 /O3。

    即使代码可以完美运行,我还是建议给你的魔法常量起一个名字以提高可读性:

    constexpr static const auto SECONDS_IN_HOUR = 3600;
    constexpr static const auto METERS_IN_KILOMETER = 1000;
    constexpr static const auto FACTOR_KILOMETER_PER_HOUR_TO_METERS_PER_SECOND = static_cast<double>(SECONDS_IN_HOUR) / static_cast<double>(METERS_IN_KILOMETER);
    

    因为这是 constexpr,所以这些应该在编译时计算,结果不会导致运行时开销。这甚至可以在没有启用优化的情况下工作。

    请注意,从 C++17 开始,这些常量是隐式内联的。因此,如果您使用旧的编译器,您可能需要进行一些更改。

    【讨论】:

      【解决方案3】:

      一些cpu会在自己的缓存中保持重复计算。

      我的建议是把结果放在那里,所以它永远不必这样做。也总是使用大括号,以防以后添加更复杂的结构。

      for(int i = 0; i <= 100; i ++) {
          std::cout << i << "meters / s:" << "=" << i * 3.6 << "Km / h" << endl;
      }
      

      对于其他更复杂的对象,可能只在需要立即得到结果的地方运行计算,或者预先计算并存储结果以供以后使用。

      【讨论】:

      • -O1 很可能已经对此进行了优化。不要建议微优化。如果有人想写3600./1000.,因为这两个数字有意义,就写吧。
      猜你喜欢
      • 1970-01-01
      • 2015-05-22
      • 1970-01-01
      • 2020-12-15
      • 2020-04-22
      • 1970-01-01
      • 2012-10-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多