【问题标题】:Suggestions for optimizing sieve of Eratosthenes in perl在 perl 中优化 Eratosthenes 筛的建议
【发布时间】:2014-12-12 01:24:35
【问题描述】:
use warnings;
use strict;

my $in=<STDIN>;
my @array=(1...$in);
foreach my $j(2...sqrt($in)){
        for(my $i=$j*2;$i<=$in;$i+=$j){
            delete($array[$i-1]);
        }
    }

delete($array[0]);
open FILE, ">","I:\\Perl_tests\\primes.dat";

foreach my $i (@array){
    if($i){
        print FILE $i,"\n";
        }
}

我确信有更好的方法来处理所有数字的数组,但是我真的不知道在 perl 中可以做到这一点。我对perl非常缺乏经验。非常感谢任何加快速度的建议。非常感谢!

【问题讨论】:

  • sub sieve{grep{@_[map$a*$_,2..@_/($a=$_)]=0if$_[$_]&gt;1}@_=0..pop} (by tily)
  • @ysth 你能解释一下它是如何工作的或解释它的作用吗?
  • 我可以,但这可能是个坏主意 :) 你的代码更容易理解
  • @ysth 好的,谢谢!您对摆脱大量占用过多内存的数组有什么建议吗?数字 99,999,999 需要将近 8GB 的​​ RAM
  • 这是一个与速度问题不同的问题;看看在长字符串上使用 Bit::Vector (或者只是 vec() )

标签: perl optimization primes sieve-of-eratosthenes


【解决方案1】:

如果您只想要素数而不关心如何获得它们,最快的解决方案是使用模块(例如ntheory)。这将大大加快速度并使用更少的内存。

我建议查看the RosettaCode Sieve task。展示了许多简单的筛子、快速字符串版本、一些奇怪的示例和几个可扩展的筛子。

即使是基本版本也比您的示例使用更少的内存,并且那里显示的向量和字符串版本使用的内存要少得多。

除非您是 Dan Bernstein,否则阿特金筛法很少是一种好方法。即使这样,它也比快速的 SoE 实现要慢。

【讨论】:

    【解决方案2】:

    这是一种相当低效的寻找素数的方法,所以除非你绝对必须使用 Erastosthenes 筛法,否则The Sieve of Atkin 可能是一种更快的寻找素数的算法。

    关于内存使用,这里有一个完善的this python answer 版本。它不是从所有整数的大前置数组中剔除数字,而是跟踪哪些素数是非素数的除数,然后在每次迭代后屏蔽下一个非素数。这意味着您可以生成尽可能多的素数,而无需使用所有 RAM 或任何比您必须使用的更多的内存。更多的代码和更多的间接性使得这个版本比你已经拥有的要慢。

    #!/usr/bin/perl
    
    use warnings;
    use strict;
    
    sub get() {
        my $this = shift;
        if ($this->{next} == 2) {
            $this->{next} = 3;
            return 2;
        }
        while (1) {
            my $next = $this->{next};
            $this->{next} += 2;
            if (not exists $this->{used}{$next}) {
                $this->{used}{$next * $next} = [$next];
                return $next;
            } else {
                foreach my $x (@{$this->{used}{$next}}) {
                    push (@{$this->{used}{$next + $x}}, $x);
                }
                delete $this->{used}{$next};
            }
        }
    }
    
    sub buildSieve {
        my $this = {
            "used" => {},
            "next" => 2,
        };
        bless $this;
        return $this;
    }
    
    my $sieve = buildSieve();
    
    foreach $_ (1..100) {
        print $sieve->get()."\n";
    }
    

    您应该能够将更好的算法与上述更高效的内存生成版本结合起来,以提出一个好的解决方案。

    如果您想详细了解该算法的工作原理,use Data::Dumper; 并在每次调用 get() 之间打印出 $sieve 非常有指导意义。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-07-03
      • 1970-01-01
      • 2018-05-29
      • 1970-01-01
      • 1970-01-01
      • 2018-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多