0
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";
        }
}

I'm sure there is a better way to do the array of all numbers however I don't really know of a way to do it in perl. I'm pretty inexperienced in perl. Any recommendations for speeding it up are greatly appreciated. Thanks a ton!

Ian
  • 245
  • 4
  • 13
  • `sub sieve{grep{@_[map$a*$_,2..@_/($a=$_)]=0if$_[$_]>1}@_=0..pop}` (by tilly) – ysth Dec 12 '14 at 02:01
  • @ysth Could you explain how that works or explain what all it does? – Ian Dec 12 '14 at 02:25
  • I could but it would probably be a bad idea :) your code is much more understandable – ysth Dec 12 '14 at 02:31
  • @ysth Okay thank you! Do you have any suggestions for getting rid of the array that with large numbers takes way too much memory? With the number 99,999,999 it takes almost 8GB of RAM – Ian Dec 12 '14 at 02:50
  • 1
    that's a different question than the speed question; look at using Bit::Vector (or just vec() on a long string) – ysth Dec 12 '14 at 03:21
  • definitely look into using a segmented sieve of Eratosthenes. don't bother about Atkin's. if deleting an element from array in Perl makes further access slow, *don't*. just set it to 0, after initially setting all entries to 1. then in the end collect all those that are still 1. – Will Ness Dec 31 '14 at 14:26

2 Answers2

1

The fastest solution is using a module (e.g. ntheory) if you just want primes and don't care how you get them. That will be massively faster and use much less memory.

I suggest looking at the RosettaCode Sieve task. There are a number of simple sieves shown, a fast string version, some weird examples, and a couple extensible sieves.

Even the basic one uses less memory than your example, and the vector and string versions shown there use significantly less memory.

Sieve of Atkin is rarely a good method unless you are Dan Bernstein. Even then, it's slower than fast SoE implementations.

DanaJ
  • 714
  • 6
  • 9
0

That's a fairly inefficient way to look for primes, so unless you absolutely have to use the Sieve of Erastosthenes, The Sieve of Atkin is probably a faster algorithm for finding primes.

With regard to the memory usage, here's a perlified version of this python answer. Instead of striking out the numbers from a big up front array of all the integers, it tracks which primes are divisors of non-prime numbers, and then masks out the next non-prime number after each iteration. This means that you can generate as many primes as you have precision for without using all the RAM, or any more memory than you have to. More code and more indirection makes this version slower than what you have already though.

#!/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";
}

You should be able to combine the better algorithm with the more memory efficient generative version above to come up with a good solution though.

If you want to see how the algorithm works in detail, it's quite instructive to use Data::Dumper; and print out $sieve in between each call to get().

Community
  • 1
  • 1
Rich L
  • 1,439
  • 2
  • 15
  • 27