{ my %prime_cache; my $max_checked; BEGIN { $prime_cache{2} = undef; $max_checked = 2; } sub is_prime { my ($to_check) = @_; sieve_up_to($to_check); return exists $prime_cache{$to_check}; } sub sieve_up_to { my ($to_check) = @_; while ( $max_checked < $to_check ) { sieve_part($to_check); } } sub sieve_part { my ($to_check) = @_; $to_check++ if !($to_check % 2); my $max_this_part = $to_check; if ( ($max_checked * $max_checked) < $to_check ) { $max_this_part = $max_checked * $max_checked; } my %to_sieve = map { $_ => undef } ($max_checked + 1 .. $max_this_part); for my $prime (keys %prime_cache) { my $base = $max_checked - ($max_checked % $prime) + $prime; while ( $base <= $max_this_part ) { delete $to_sieve{$base}; $base += $prime; } } while ( my $new_prime = each %to_sieve ) { $prime_cache{$new_prime} = undef; } $max_checked = $max_this_part; } }