我开始探索Project Euler。和其他许多人一样,我认为我需要制作一个素数发生器。问题是:PHP不喜欢大数字。如果我使用标准Sieve of Eratosthenes function,并将限制设置为200万,它将崩溃。它不喜欢创建那种大小的数组。可以理解的。
所以现在我正在尝试优化它。我找到的一种方法是,不是创建一个包含200万个变量的数组,而是只需要100万个(只有奇数可以是素数)。但是现在它崩溃了,因为它超过了最大执行时间......
function getPrimes($limit) {
$count = 0;
for ($i = 3; $i < $limit; $i += 2) {
$primes[$count++] = $i;
}
for ($n = 3; $n < $limit; $n += 2) {
//array will be half the size of $limit
for ($i = 1; $i < $limit/2; $i++) {
if ($primes[$i] % $n === 0 && $primes[$i] !== $n) {
$primes[$i] = 0;
}
}
}
return $primes;
}
该功能有效,但正如我所说,它有点慢......有什么建议吗?
我发现让它快一点的一件事就是切换循环。
foreach ($primes as $value) {
//$limitSq is the sqrt of the limit, as that is as high as I have to go
for ($n = 3; $n = $limitSq; $n += 2) {
if ($value !== $n && $value % $n === 0) {
$primes[$count] = 0;
$n = $limitSq; //breaking the inner loop
}
}
$count++;
}
另外设置时间和内存限制(感谢Greg),我终于设法得到了答案。 phjew。
答案 0 :(得分:4)
不太了解算法:
$limit/2
$primes[$i] !== $n
是否会更快。旁注,您可以使用set_time_limit()
为其提供更长的运行时间,并使用
ini_set('memory_limit', '128M');
假设您的设置允许此操作,当然 - 在共享主机上您可能会受到限制。
答案 1 :(得分:3)
来自Algorithmist's proposed solution
这是对标准的修改 Eratosthenes的筛子。这将是 效率极低,用得太多了 很多记忆和时间,运行 标准筛一直到n。 但是,没有复合数小于 或等于n将有一个因素 大于sqrt {n}, 所以我们只需知道所有素数 达到这个限制,这不是更大 比31622(平方根10 ^ 9)。这个 用筛子完成。的然后, 对于每个查询,我们只筛选 给出的范围,使用我们的 预先计算的素数表 消除综合数字。
此问题也出现在UVA和Sphere的在线评委中。 Here's how it's enunciated on Sphere.
答案 2 :(得分:2)
您可以使用位字段存储筛子。也就是说,除了你把布尔值打包成一个大整数之外,它与一系列布尔值大致相同。例如,如果你有8位整数,你将每整数存储8位(布尔值),这将进一步减少你的空间需求。
此外,使用位字段可以使用位掩码执行筛选操作。例如,如果您的筛子保留所有数字(不仅仅是奇数),您可以构造一个b01010101的位掩码,然后您可以对阵列中的每个元素。对于三个,您可以使用三个整数作为掩码:b00100100 b10010010 b01001001。
最后,您无需检查低于$n
的数字,实际上您无需检查小于$n*$n-1
的数字。
答案 3 :(得分:0)
一旦你知道这个数字不是素数,我就会退出回路。我不知道php,但你需要一个语句,如C语言中的中断或Perl中的最后一个语句。
如果那个不可用,我会设置一个标志并用它来退出inter循环作为继续interloop的条件。这样可以加快执行速度,因为如果它不是素数,你不会检查$ limit / 2项。
答案 4 :(得分:0)
如果你想要速度,不要在这个上使用PHP:P
不,说真的,我真的很喜欢PHP而且它是一种很酷的语言,但它根本不适合这种算法