【发布时间】:2019-06-07 02:35:46
【问题描述】:
我编写了一个小 C 程序来计算素数,现在尝试尽可能优化代码。
在程序的第一个版本中,我检查一个数字是否为偶数(模 2),如果是,我将继续下一个数字。
在我的第二次修订中,我尝试通过将要检查的数字增加 2 来仅检查奇数是否可能是素数(所以我将从 3 开始,然后检查 5,然后检查 7,然后检查 9,然后检查 11 等) .
我认为这会更快,因为我已经用我的代码对模 2 进行了额外检查,并简单地将其替换为加法。 然而,令我惊讶的是,仅检查奇数的代码在大多数情况下运行速度比检查所有数字的实现慢一点。
这是代码(它包含我在 cmets 中的修订之间所做的更改,无论它说的是//CHANGE)
#include <stdio.h>
#include <stdbool.h>
#include <math.h>
unsigned long i = 3; //CHANGE No 1 - it was i = 2;
bool hasDivisor(unsigned long number)
{
//https://stackoverflow.com/questions/5811151/why-do-we-check-up-to-the-square-root-of-a-prime-number-to-determine-if-it-is-pr
unsigned long squareRoot = floor(sqrt(number));
//we don't check for even divisors - we want to check only odd divisors
//CHANGE No 2 - it was (number%2 ==0)
if(!((squareRoot&1)==0)) //thought this would boost the speed
{
squareRoot += 1;
}
for(unsigned long j=3; j <= squareRoot; j+=2)
{
//printf("checking number %ld with %ld \n", number, j);
if(number%j==0)
{
return true;
}
}
return false;
}
int main(int argc, char** argv)
{
printf("Number 2 is a prime!\n");
printf("Number 3 is a prime!\n");
while(true)
{
//even numbers can't be primes as they are a multiple of 2
//so we start with 3 which is odd and contiously add 2
//that we always check an odd number for primality
i++; //thought this would boost the speed instead of i +=2;
i++; //CHANGE No 3 - it was a simple i++ so eg 3 would become 4 and we needed an extra if(i%2==0) here
//search all odd numbers between 3 and the (odd ceiling) sqrt of our number
//if there is perfect division somewhere it's not a prime
if(hasDivisor(i))
{
continue;
}
printf("Number %ld is a prime!\n", i);
}
return 0;
}
我正在使用 Arch Linux x64 和 GCC 版本 8.2.1 并编译:
gcc main.c -lm -O3 -o primesearcher
虽然我也用 O1 和 O2 进行了测试。
我正在使用以下命令进行“基准测试”:
./primesearcher & sleep 10; kill $!
它运行程序 10 秒,并在这段时间内向终端输出素数,然后终止它。 我显然尝试让程序运行更多(30、60 和 180 秒),但结果大约有 9/10 的时间有利于版本检查偶数(模 2 版本在被杀死之前发现了更大的素数) .
知道为什么会这样吗? 最后可能代码有问题?
【问题讨论】:
-
代码运行正常,那么这个问题更适合 CodeReview 吗?
-
数字 1 不是素数
-
啊,请不要通过更改您发布的代码让 cmets 看起来很愚蠢。我不明白你为什么要搞乱平方根。你可以有
unsigned long squareRoot = round(sqrt(number));,squareRoot是奇数还是偶数都没有关系。 -
你是否完全达到限制并不重要。仅当您大于限制时才需要停止。无论您的最后一次检查是
limit-1还是limit都没有任何区别。反正你只能打其中一个。 -
要回答为什么一个版本的程序运行速度比另一个版本快,我们需要查看两个版本。一方面,您没有展示您声称速度更快的程序版本,另一方面,您提供了您声称速度较慢的程序的 多个 版本。这不行。由于您似乎广泛关注优化而不是某个特定更改,因此我认为 Code Review 会比当前问题更好地为您服务,而不是像 WeatherVane 已经建议的那样。
标签: c optimization primes mathematical-optimization