需要帮助来了解实现Eratosthenes筛选的Perl代码

时间:2014-05-12 19:38:28

标签: perl sieve-of-eratosthenes

我发现以下代码用Perl编写了关于Eratosthenes的Sieve(一种在给定数字范围内找到素数的算法)并且它工作正常,但我不明白。有人可以为我评论一下,所以我会更好地了解素数是如何找到的吗?

$max= 120; 
@primes= ();
@tested= (1);
$j= 1;
while ($j < $max) {
   next if $tested[$j++];
   push @primes, $j;
   for ($k= $j; $k <= $max; $k+=$j) {
      $tested[$k-1]= 1;
   }
}
print "@primes\n";

2 个答案:

答案 0 :(得分:3)

我会像下面那样重写(清理)该脚本,以使其更清晰。

以此为例,如果给变量赋予变量有意义的名称,代码就可以自我记录:

use strict;
use warnings;

my $max = 120;
my @primes;
my @notprime;

for my $num (2..$max) {
    next if $notprime[$num];
    push @primes, $num;
    for (my $multiple = 2 * $num; $multiple <= $max; $multiple += $num) {
        $notprime[$multiple] = 1;
    }
}
print "@primes\n";

关于Sieve of Eratosthenes的维基百科文章将完全解释该算法,并提供关于该过程的非常少的视觉效果。但是,摘要就是这样:

  • 遍历从2到最大的所有整数。
  • 如果一个整数没有被标记为notprime,那么它就是素数!
  • 然后循环遍历所识别的素数的所有倍数,以便我们可以将它们标记为非素数。

答案 1 :(得分:1)

$max= 120; 
@primes= ();

$tested可能会更好地命名为$nonprime。虽然我们将1放入数组中,但它实际上并没有做任何有用的事情......它同样可以留空。

此外,@tested不是非素数列表,而是一个布尔值列表,其索引是非素数。如果出于某种原因,您想将2标记为非素数,则必须执行以下操作:@tested = (1,1);

@tested= (1);
$j= 1;

扫描1到120之间的所有整数。

while ($j < $max) {

如果我们已经检查了这个数字的原始性并且失败了,请重新启动循环以检查下一个数字。

   next if $tested[$j++];

我们现在知道j是素数,因为我们没有将它标记为非素数,因此我们可以将它添加到列表的末尾。因此,最终列表将按升序排列。

   push @primes, $j;

扫描此数组和数组末尾之间的每个剩余数字。我们每次增加新的素数,所以我们基本上跨越了$j的所有倍数

   for ($k= $j; $k <= $max; $k+=$j) {

将每个倍数标记为已测试。我们知道它不能是素数,因为它有$j作为因素。

      $tested[$k-1]= 1;
   }
}

脚本的其余部分留给读者练习。

print "@primes\n";