DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

Perl Script to give prime numbers upto the target number

— ny_wk

Perl Script to give prime numbers upto the target number

To generate prime numbers up to N in Perl, loop through each candidate and test divisibility (trial division), or use the much faster Sieve of Eratosthenes to mark off multiples in one pass. The complete, runnable scripts below do both, with benchmarks and edge cases.

The Problem: Finding Primes up to a Target

A prime number is an integer greater than 1 whose only positive divisors are 1 and itself. So 2, 3, 5, 7, 11 and 13 are prime, while 4, 6, 8, 9 and 10 are not because they factor into smaller numbers. The classic exercise is simple to state: given a target N, print every prime from 2 up to and including N.

This shows up constantly in real work. System administrators use prime generation for quick hash-table sizing, load-balancing buckets, and synthetic test data; it is also the gateway problem for learning algorithmic complexity. Perl handles it gracefully because it makes integer arithmetic, ranges, and array tricks concise. The catch is that the obvious approach is slow, and most beginners write a version that gets noticeably sluggish well before N reaches a million. The goal here is code that is both correct and fast.

Approach 1: Trial Division (the intuitive method)

The most direct way to test whether a number is prime is trial division: try to divide the candidate by smaller integers and see if any divides it evenly (remainder zero). If one does, the candidate is composite; if none does, it is prime. In Perl the modulo operator % gives the remainder, so $count % $j == 0 means $j divides $count exactly.

A naive loop checks every divisor from 2 up to $count - 1. That works, but it does far more work than necessary. Two observations cut the cost dramatically:

  • Stop at the square root. If n has a divisor larger than its square root, it must also have a matching one smaller than the square root, so you never need to test past sqrt(n).
  • Skip even numbers. After checking 2, every other prime is odd, so you can step divisors by 2 and skip half the candidates entirely.

Here is a clean, idiomatic Perl rewrite that incorporates both optimizations and reads input safely:

#!/usr/bin/perl
use strict;
use warnings;

print "Up to what number should I find primes? ";
my $n = <STDIN>;
chomp $n;

die "Please enter a non-negative integer.\n"
    unless defined $n && $n =~ /^\d+$/;

# Returns true if $num is prime.
sub is_prime {
    my ($num) = @_;
    return 0 if $num < 2;        # 0 and 1 are not prime
    return 1 if $num == 2;        # 2 is the only even prime
    return 0 if $num % 2 == 0;    # skip all other evens
    for (my $d = 3; $d * $d <= $num; $d += 2) {
        return 0 if $num % $d == 0;
    }
    return 1;
}

for my $count (2 .. $n) {
    print "$count is a prime number\n" if is_prime($count);
}

Code Walkthrough

  1. use strict; use warnings; turns on Perl's safety net. It forces variable declarations with my and warns about likely mistakes such as using an uninitialized value. Always start scripts with both.
  2. Read and clean the input. my $n = <STDIN>; reads a line, which still contains the trailing newline, so chomp $n; removes it. The die unless ... =~ /^\d+$/ line validates that the user actually typed a non-negative whole number and aborts politely otherwise.
  3. The is_prime subroutine centralizes the test. Pulling the logic into a named sub makes the program readable and lets you reuse the same check elsewhere. It rejects everything below 2, special-cases 2, and discards even numbers immediately.
  4. The square-root loop. The condition $d * $d <= $num is the key efficiency line. Comparing $d * $d to $num avoids repeatedly calling sqrt and keeps the math in integers. Stepping $d += 2 tests only odd divisors.
  5. The driver loop walks every integer from 2 to $n with the range operator 2 .. $n and prints those that pass the test.

Compared with the original version that looped divisors all the way to $count - 1, this rewrite removes a fragile shared flag variable and tests dramatically fewer divisors, while still printing the same results.

Approach 2: The Sieve of Eratosthenes (the fast method)

When you need all primes up to N rather than testing one number, the Sieve of Eratosthenes is the right tool. Instead of asking "is this number prime?" one at a time, the sieve flips the problem around: assume every number is prime, then cross out the multiples of each prime you find. Whatever survives is prime.

The procedure, dating back over two thousand years to the Greek mathematician Eratosthenes, is:

  • Create a boolean list for 0 .. N, marking 0 and 1 as not prime and everything else as a candidate.
  • Starting at the first prime, 2, cross out all of its multiples: 4, 6, 8, and so on.
  • Advance to the next number still marked prime and cross out its multiples.
  • Repeat until you pass sqrt(N); the numbers left marked are the primes.

Here is a complete sieve implementation in Perl:

#!/usr/bin/perl
use strict;
use warnings;

print "Up to what number should I find primes? ";
my $n = <STDIN>;
chomp $n;

die "Please enter a non-negative integer.\n"
    unless defined $n && $n =~ /^\d+$/;

my @primes = sieve($n);
print "Primes up to $n:\n";
print "$_\n" for @primes;
print "Found ", scalar(@primes), " primes.\n";

sub sieve {
    my ($limit) = @_;
    return () if $limit < 2;

    # is_composite[$i] stays false while $i is still a prime candidate
    my @is_composite;

    for (my $i = 2; $i * $i <= $limit; $i++) {
        next if $is_composite[$i];
        # start crossing out at $i*$i; smaller multiples were
        # already handled by smaller primes
        for (my $m = $i * $i; $m <= $limit; $m += $i) {
            $is_composite[$m] = 1;
        }
    }

    return grep { !$is_composite[$_] } 2 .. $limit;
}

Why the Sieve Is Faster

  1. No division at all. The sieve only adds ($m += $i). Addition is cheaper than the repeated modulo operations trial division performs.
  2. Work is shared. Crossing out the multiples of 2 helps decide every even number at once, so effort is amortized across the whole range instead of being repeated per candidate.
  3. Start the inner loop at $i * $i. Any multiple of $i smaller than $i * $i already has a smaller prime factor and was crossed out earlier, so beginning at the square is a free speedup.
  4. Outer loop stops at sqrt(limit). Once $i * $i exceeds the limit, every remaining composite has already been marked, so there is nothing left to do.
  5. grep collects the survivors. The final grep { !$is_composite[$_] } 2 .. $limit returns exactly the indices never marked as composite, in order.

Efficiency and Complexity Compared

The difference between the two methods grows quickly with N. Trial division across the whole range costs roughly O(N * sqrt(N) / log N) operations in practice, while the sieve runs in O(N log log N) time, which is very close to linear. The trade-off is memory: the sieve needs an array proportional to N, whereas trial division uses almost none.

MethodTime complexityMemoryBest for
Naive trial division (to n-1)O(N²)O(1)tiny N, teaching only
Trial division (to √n, odds only)~O(N·√N)O(1)one-off tests, huge N, low memory
Sieve of EratosthenesO(N log log N)O(N)listing all primes up to N

As a rough guide, the optimized trial-division script handles N up to a few hundred thousand comfortably, while the sieve happily lists every prime below ten million in a second or two on a modern machine. If you ever need primes in the billions, switch to a segmented sieve, which processes the range in cache-friendly chunks and keeps memory bounded.

Edge Cases and Common Pitfalls

Most prime-finder bugs come from a handful of boundary mistakes. Watch for these:

  • 1 is not prime. By definition a prime needs exactly two distinct divisors, and 1 has only one. Any test must return false for 0 and 1.
  • 2 is prime and is even. It is the only even prime, so handle it explicitly before skipping evens, or your script will wrongly drop it.
  • Forgetting chomp. Input from <STDIN> carries a newline. Without chomp, the value may misbehave in numeric comparisons and trigger warnings.
  • Off-by-one on the limit. Use 2 .. $n (inclusive) if N itself should be tested; 2 .. $n-1 silently drops it.
  • Integer overflow on the square test. For very large numbers, $d * $d stays safe in Perl's floating/integer handling for typical inputs, but if you push into astronomically large values consider Math::BigInt.
  • Non-numeric input. Always validate with a regex like /^\d+$/ so a stray letter does not produce a confusing crash.
  • Sieve memory. A sieve for a billion needs a large array. For that scale reach for a bit vector (vec) or a segmented approach instead of a plain Perl array.

For production-grade work, you do not have to roll your own at all. The CPAN modules Math::Prime::Util and ntheory provide blazing-fast, well-tested routines such as primes() and is_prime(). Install one with cpan Math::Prime::Util and call use ntheory qw(primes); my @p = @{ primes($n) };. Use the hand-written versions to learn the algorithms; use the library when speed and correctness matter most.

How to Run and Verify the Scripts

Save either listing to a file, for example primes.pl. Perl ships with macOS and most Linux distributions; on Windows install Strawberry Perl. Then run it from a terminal:

perl primes.pl

On Linux or macOS you can also make it directly executable:

chmod +x primes.pl
./primes.pl

Type a target such as 30 when prompted, and you should see exactly:

2, 3, 5, 7, 11, 13, 17, 19, 23, 29

To verify correctness, sanity-check the known counts: there are 25 primes below 100, 168 below 1,000, and 1,229 below 10,000. If your script's count for those limits matches, the logic is sound. You can confirm with a quick one-liner:

perl primes.pl <<< "100" | grep -c prime

To benchmark the sieve against trial division, wrap each in Perl's built-in Benchmark module or simply time the run with time perl primes.pl for a large limit. The gap becomes obvious past about N = 100000, where the sieve finishes near-instantly while trial division begins to lag.

Key Takeaways

  • Trial division is the intuitive method: test each candidate against divisors up to its square root, stepping by 2 to skip evens.
  • The Sieve of Eratosthenes crosses out multiples in one sweep and is far faster (O(N log log N)) for listing all primes up to N.
  • Always handle the edge cases: 0 and 1 are not prime, 2 is the only even prime, and chomp your input.
  • Choose by need: trial division for low memory or one-off tests, the sieve for bulk lists, a segmented sieve or Math::Prime::Util for very large ranges.
  • Verify with known prime counts (25 under 100, 168 under 1,000) before trusting any new implementation.

Frequently Asked Questions

Why only check divisors up to the square root?

Divisors come in pairs that multiply to n. If both were larger than sqrt(n), their product would exceed n, which is impossible. So if a number has any divisor at all, at least one of them is no greater than sqrt(n) and you will have already found it. Checking past the square root is wasted work.

Is the Sieve of Eratosthenes always better than trial division?

For listing every prime up to a limit, yes, it is dramatically faster. But it uses memory proportional to N, so for a single primality test on a huge isolated number, or when memory is tight, optimized trial division (or a probabilistic test) can be the better choice.

How do I make the Perl sieve handle very large N without running out of memory?

Replace the plain array with a bit vector using Perl's vec function, which stores each flag in a single bit, or switch to a segmented sieve that processes one window of the range at a time. For real workloads, the CPAN module Math::Prime::Util already implements these efficiently.

Does Perl have a built-in function to generate primes?

The core language does not, but CPAN does. Install Math::Prime::Util (which provides the ntheory namespace) and call primes($n) for a fast, tested list. It is the recommended choice for production code.

If you found this walkthrough useful, subscribe to @explorenystream on YouTube for more practical coding and system-admin tutorials.