C 仅使用奇数因子计算素数的速度较慢

C 仅使用奇数因子计算素数的速度较慢,c,optimization,primes,mathematical-optimization,C,Optimization,Primes,Mathematical Optimization,我已经写了一个小的C程序来计算素数,现在我试着尽可能地优化代码 在程序的第一次修订中,我检查一个数字是否为偶数(模2),如果是,我将继续下一个数字 在我的第二次修订版中,我尝试通过将我要检查的数字增加2来检查奇数是否可能是素数(因此我将从3开始,然后检查5,然后检查7,然后检查9,然后检查11等等) 我想这会快得多,因为我用我的代码对模2进行了额外的检查,并简单地用一个加法替换了它。 然而,令我惊讶的是,代码只检查奇数,在大多数情况下比检查所有数字的实现运行得稍微慢一点 下面是代码(它包含我在注

我已经写了一个小的C程序来计算素数,现在我试着尽可能地优化代码

在程序的第一次修订中,我检查一个数字是否为偶数(模2),如果是,我将继续下一个数字

在我的第二次修订版中,我尝试通过将我要检查的数字增加2来检查奇数是否可能是素数(因此我将从3开始,然后检查5,然后检查7,然后检查9,然后检查11等等)

我想这会快得多,因为我用我的代码对模2进行了额外的检查,并简单地用一个加法替换了它。 然而,令我惊讶的是,代码只检查奇数,在大多数情况下比检查所有数字的实现运行得稍微慢一点

下面是代码(它包含我在注释中的修订之间所做的更改,无论它在哪里显示//更改)

虽然我也测试了O1和O2

我正在使用下面的命令进行“基准测试”:

./primesearcher & sleep 10; kill $! 
它运行程序10秒,并在该时间内向终端输出素数,然后将其终止。 很明显,我试着让程序运行更长的时间(30、60和180秒),但结果是大约9/10的时间支持版本检查偶数(模2版本在被杀死之前发现了一个更大的素数)

你知道为什么会这样吗? 也许最终代码有问题?

如果(!((平方根&1)==0))
比没有测试的代码慢,因为它很少有好处

请记住,对于大多数
number
,由于
number%j
测试提前返回,因此从未达到迭代限制。随着
数量的增加,素数往往变得稀少

很少的额外迭代不会被测试的重复成本所抵消

比较
!((平方根&1)==0)
to
number%2==0
is

OP的测试速度的方法在差异很小时容易出错:“大多数时候运行稍微慢一点”显示了不一致性

大量的时间都在
printf()
中。为了比较基本计算性能,需要消除I/O

kill
也不是那么精确

相反,当
i
达到4000000000这样的值时,形成一个循环来停止,并等待该时间


该守则还有其他弱点:

无符号长平方根=地板(sqrt(数字))number
转换为
double
时的舍入以及
sqrt()
例程的不精确性,code>可能会为大的
number
创建错误的根。OP解决了数学算法的需要。然而,考虑到实际计算的局限性,这种C代码实现很容易失败

相反,建议

// Prime test for all unsigned long number
bool isPrime(unsigned long number) {
  if (number % 2 == 0) {  // This can be eliminated if `number` is always odd.
    return number == 2;
  }

  for (unsigned long j = 3; j <= number/j; j += 2) {
    if (number%j == 0) {
      return false;
    }
  }

  return number > 2;
}

使用全局
i
这里是一种弱编码风格。建议改为重新编码和传递函数


要获得更实质性的改进,请查看并保存以前发现的素数列表,并测试这些素数,而不是所有奇数


Prime testing是一个深入的主题,有许多更高级的想法。

代码正在运行,所以这个问题更适合CodeReview吗?数字1不是primeAh请不要通过更改您发布的代码使评论看起来很愚蠢。我不明白你为什么要摆弄平方根。您可以有
无符号长平方根=round(sqrt(number))
平方根是奇数还是偶数并不重要。如果你精确地达到了极限也不重要。您只需要在超出限制时停止。您的上一次检查是
limit-1
还是
limit
没有任何区别。无论如何,你只能点击其中一个。要回答为什么一个版本的程序运行得比另一个版本快,我们需要查看两个版本。一方面,您没有提供声称更快的程序版本,另一方面,您提供了声称较慢的程序的多个版本。这不行。由于您似乎更关注优化,而不是一个具体的变化,我认为,像风向标已经建议的那样,有了这样的关注,您会比现在的问题更好。谢谢您的回答。不幸的是,我无法为唯一的赔率数字检查器获得更好的执行时间。我在这里做了一个在线差异,看看代码现在是如何应用您的建议的(一个版本仍在检查偶数,另一个版本仅检查赔率)。由于不再使用printf,我现在使用time命令来测量性能。我使用了45000000的硬限制,因为我不想让它花费太多时间。这两个版本都需要49秒才能再次完成,而对于一秒钟的片段,赔率版本要慢一些。可以在此处找到差异:@user-2147482617对于45000000,埃拉托斯烯的筛可能是fastest@user-2147482617一个未经优化的埃拉托斯烯筛(45000000)耗时不到2秒。埃拉托斯烯(1000000000)的筛取时间为24秒。
./primesearcher & sleep 10; kill $! 
// Prime test for all unsigned long number
bool isPrime(unsigned long number) {
  if (number % 2 == 0) {  // This can be eliminated if `number` is always odd.
    return number == 2;
  }

  for (unsigned long j = 3; j <= number/j; j += 2) {
    if (number%j == 0) {
      return false;
    }
  }

  return number > 2;
}
// printf("Number %ld is a prime!\n", i);
printf("Number %lu is a prime!\n", i);