Pure Programmer
Blue Matrix


Cluster Map

Project: Number of Primes

The number of primes equal to or less than a number x is denoted by the function `π(x)`. There is no easy way to compute this function although there are ways to compute a list of primes. Use the SieveOfEratosthenes project to generate a file of prime numbers less than 1,000,000. Then write a function `π(x)` that searches the file for the answer. The function should return the number of primes read before a value greater than x is found. To improve efficiency for subsequent calls to `π(x)` you should only read the file the first time the function is called and store the prime values in an array. This way subsequent calls to `π(x)` don't need to re-read the file. Write a test program to print the values of `π(x)` for x that are powers of 2 up to `2^19`. Will this approach work if you want to compute values for x up to 1,000,000,000 by generating an approprite file of primes? Modify the program to use an estimate `x/(ln x - 1)` for values greater than are found in the primes data file. Test by computing `π(x)` up to `2^30`.

See [[How Many Primes Are There?]]
See SieveOfEratosthenes

Output
$ perl NumberOfPrimes.pl Unable to parse: Encountered unexpected character '207' use POSIX qw(floor); use Utils; use strict; use warnings; our $PRIME_FILE = "../../data/text/primes1M.txt"; our $primes = []; sub readPrimes { my ($filename) = @_; print "Reading prime file ", $filename, "...\n"; my $ifh; my $isGood = open($ifh, "<", $filename); if (!$isGood) { die Error::IOException->new("Problem opening input file!"); } binmode($ifh, ":utf8"); my $line; while ($line = <$ifh>) { chomp($line); my $p = Utils::stoiWithDefault($line, 0); if ($p != 0) { push(@{$primes}, $p); } } close($ifh); } sub binarySearch { my ($list, $value) = @_; if ($value < $primes->[0]) { return -1; } if ($value > $primes->[-1]) { return scalar(@{$primes}); } my $left = 0; my $right = scalar(@{$list}) - 1; while ($left <= $right) { my $m = int(($left + $right) / 2); if ($list->[$m] < $value) { $left = $m + 1; } elsif ($list->[$m] > $value) { $right = $m - 1; } else { return $m + 1; } } return $left; } sub π { my ($x) = @_; my $pos = scalar(@{$primes}); if ($pos != 0) { $pos = binarySearch($primes, $x); } if ($pos == scalar(@{$primes})) { return floor($x / (log($x) - 1) + 0.5); } else { return $pos; } } MAIN: { binmode(STDOUT, ":utf8"); binmode(STDERR, ":utf8"); binmode(STDIN, ":utf8"); try { readPrimes($PRIME_FILE); my $x = 1; for (my $i = 1; $i <= 30; ++$i) { $x *= 2; print Utils::messageFormat("π(\{0:d\}) = \{1:d\}", $x, π($x)), "\n"; } } catch (Error::Simple $ex) { print "Error reading input file!\n"; } }

Solution