让我们从声明代码可读性胜过微优化开始,我们应该将其留给编译器。这只是一个奇怪的案例,其中的细节似乎不符合一般建议

因此,搞砸了素数生成器函数,并提出了一个怪异的行为,其中“!=”被推荐为最有效的实际上实际上是效率最低的,而“
C#

private static void Main(string[] args) {
  long totalTicks = 0;
  for (int i = 0; i < 100; ++i) {
    var stopWatch = Stopwatch.StartNew();
    PrintPrimes(15000);
    totalTicks += stopWatch.ElapsedTicks;
  }
  Console.WriteLine("\n\n\n\nTick Average: {0}", totalTicks / 100);
  Console.Read();
}

private static void PrintPrimes(int numberRequired) {
  if (numberRequired < 1)
    return;
  Console.Write("{0}\t", 2);
  int primeTest = 3;
  /****** UPDATE NEXT TWO LINES TO TEST FOR != *****/
  int numPrimes = 2;  // set numPrimes = 1 for !=
  while (numPrimes <= numberRequired) {  // switch <= to !=
    if (IsPrime(primeTest)) {
      Console.Write("{0}\t", primeTest);
      ++numPrimes;
    }
    primeTest += 2;
  }
}

private static bool IsPrime(int test) {
  for (int i = 3; i * i <= test; i = 2 + i)
    if (test % i == 0)
      return false;
  return true;
}

输出:
<= 1319991
!= 1321251

同样在C++中(在另一台计算机上)
include <cstddef>
#include <limits>

int main() {
  for(size_t i(0) ; i <= 10000000000 ; ++i);
}

输出:
<=

real        0m16.538s
user        0m16.460s
sys        0m0.000s
~ [master] $ vim d.cc

!=

real        0m16.860s
user        0m16.780s
sys        0m0.000s

循环运行相同的时间。是否有针对<=的优化(不适用于!=),或者是某些奇怪的cpu行为?

最佳答案

假设结果是相同的迭代次数,则没有区别是没有意义的。

如果我们假设它是x86处理器,则!=会变成jne(或je,具体取决于"is"或“不是”的哪一侧跳转[1])。 <=将执行jlejgt,具体取决于循环进行的方式。尽管指令不同,但其他处理器具有相同种类的指令。

我怀疑您有测量错误。 16秒之内的相差不到0.2秒并不是一个很大的差别,那时候您可能只是有更多的网络数据包,硬盘中断或某些后台进程在运行。

[1]例如,具有一组固定的迭代的for循环通常仅具有“如果不是true,则跳转到循环的开始”,并且while循环也是如此。

我只是在我的机器上运行了它:

bool IsPrime(int test) {
  for (int i = 3; i * i <= test; i = 2 + i)
    if (test % i == 0)
      return false;
  return true;
}

void PrintPrimes(int numberRequired) {
  if (numberRequired < 1)
    return;
  int primeTest = 3;
  /****** UPDATE NEXT TWO LINES TO TEST FOR != *****/
  int numPrimes = 2;  // set numPrimes = 1 for !=
  while (numPrimes != numberRequired) {  // switch <= to !=
    if (IsPrime(primeTest)) {
      ++numPrimes;
    }
    primeTest += 2;
  }
}

int  main()
{
  long totalTicks = 0;
  for (int i = 0; i < 100; ++i) {
    PrintPrimes(15000);
  }
}

g++ -O3 primes.cpp编译。在主循环中使用!=<=之间的区别并不明显。 !=的最快时间是3.326s,<= 3.329的时间最慢,!=是3.332,而<=的时间是3.335s。之前在我的计算机上运行过许多基准测试后,我知道毫秒数没有意义,因此我要说两者都花费了3.33秒。

并确认一下:
--- primesne.s  2013-04-30 23:52:10.840513380 +0100
+++ primesle.s  2013-04-30 23:52:35.457639603 +0100
@@ -46,7 +46,7 @@
 .L3:
    addl    $2, %esi
    cmpl    $15000, %edi
-   jne .L10
+   jle .L10
    subl    $1, %r9d
    jne .L2
    xorl    %eax, %eax

“不等于”和“小于或等于”之间的全部差异是jnejle指令-这是该代码的两个变体的g++的汇编输出-也是diff的ENTIRE输出。

07-24 14:15