【问题标题】:Which is more efficient inside a loop condition, i<sqrtN (pre-calculated) or i*i<N, in C++?在 C++ 中,在循环条件 i<sqrtN(预先计算)或 i*i<N 中哪个更有效?
【发布时间】:2020-10-12 02:01:41
【问题描述】:

假设给定整数 N,我需要运行 N 次循环平方根。

在 C++ 中,我可以通过这两种方式来做到这一点——

1)

long long sqrtN = std::sqrt(N);
for (long long i=1; i < sqrtN; i++) {
    // some piece of code
}
for (long long i=1; i * i < N; i++) {
    // some same piece of code
}

我发现 std::sqrt() 具有 O(logn) 复杂度。 另外,我相信数字的乘法只是一个常数时间的运算。

所以,感觉第二个版本更快。但是,对于非常大的 n 值,第二版中的恒定时间可能很重要。

因此,我不确定哪种方式更有效?

【问题讨论】:

  • 为什么不运行基准测试?
  • sqrt 可以只是一条汇编指令,例如 sqrtsd
  • @Evg: ...这仍然可能非常昂贵。汇编指令的数量并不是一个很好的性能指标。
  • @DevSolar,同意。关键是sqrt(n) 不一定是O(log n)
  • 还要注意++ii++ 快。 ;-)

标签: c++ loops conditional-statements


【解决方案1】:

我发现 std::sqrt() 具有 O(logn) 复杂度。另外,我相信数字的乘法只是一个常数时间的运算。

到目前为止一切顺利。你漏掉了一个细节。第一次调用sqrt 一次,第二次在每次循环迭代中计算i*i。因此它实际上是O(log n)O(sqrt(n)),即计算循环外的边界获胜,因为log n &lt; sqrt(n)

要真正知道什么更有效,渐近复杂度只能给您初步提示,当您将n 增加到无穷大时会发生什么。对于真实案例,您应该查看编译器和配置文件的输出。

对于复杂性主要是理论上的兴趣,我怎么强调都不为过。对于真正的代码,无法进行分析和测量。 O(N) 算法胜过 O(logN) 算法的可能性不大,因为渐近复杂度完全忽略了任何常数因素。

PS:不要过早优化。编写代码以提高可读性并将优化留给编译器。只有当您测量并发现花费太多时间来计算您需要做的事情的循环边界时。考虑到i*i 是一条指令,而循环体可能远不止于此(参见阿姆达尔定律)。

【讨论】:

    【解决方案2】:

    我相信您自己已经回答了大部分问题:

    • 计算N 的平方根具有O(Log(N)) 复杂度
    • 计算i 的平方可能很快,但您需要这样做sqrt(N) 次,因此复杂度大于O(sqrt(N))

    由于O(Log(N))小于O(sqrt(N)),我会说第一种方法是最快的。

    【讨论】:

      【解决方案3】:

      这样想 - 计算平方根只发生一次。当您多次执行循环时,这个时间基本上是隐藏的。然而,平方具有与循环迭代次数有关的线性复杂度,即 O(sqrt(N)),并且对于较大的 N 会更慢。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-04
        • 1970-01-01
        • 2011-05-14
        • 2010-10-08
        • 1970-01-01
        • 2020-05-24
        相关资源
        最近更新 更多