The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
#!/usr/bin/env perl
use strict;
use warnings;

use Test::More;
use Math::Prime::Util qw/prime_count prime_count_lower prime_count_upper prime_count_approx/;

my %pivals = (
                1000 =>                168,
               10000 =>               1229,
              100000 =>               9592,
             1000000 =>              78498,
            10000000 =>             664579,
           100000000 =>            5761455,
          1000000000 =>           50847534,
         10000000000 =>          455052511,
        100000000000 =>         4118054813,
       1000000000000 =>        37607912018,
       2000000000000 =>        73301896139,
       3000000000000 =>       108340298703,
       4000000000000 =>       142966208126,
       5000000000000 =>       177291661649,
       6000000000000 =>       211381427039,
       7000000000000 =>       245277688804,
       8000000000000 =>       279010070811,
       9000000000000 =>       312600354108,
      10000000000000 =>       346065536839,
      20000000000000 =>       675895909271,
      30000000000000 =>      1000121668853,
      40000000000000 =>      1320811971702,
      50000000000000 =>      1638923764567,
      60000000000000 =>      1955010428258,
      70000000000000 =>      2269432871304,
      80000000000000 =>      2582444113487,
      90000000000000 =>      2894232250783,
     100000000000000 =>      3204941750802,
     200000000000000 =>      6270424651315,
     300000000000000 =>      9287441600280,
     400000000000000 =>     12273824155491,
     500000000000000 =>     15237833654620,
     600000000000000 =>     18184255291570,
     700000000000000 =>     21116208911023,
     800000000000000 =>     24035890368161,
     900000000000000 =>     26944926466221,
    1000000000000000 =>     29844570422669,
   10000000000000000 =>    279238341033925,
   20000000000000000 =>    547863431950008,
   40000000000000000 =>   1075292778753150,
  100000000000000000 =>   2623557157654233,
 1000000000000000000 =>  24739954287740860,
 2000000000000000000 =>  48645161281738535,
 3000000000000000000 =>  72254704797687083,
 4000000000000000000 =>  95676260903887607,
 4185296581467695669 => 100000000000000000,
 5000000000000000000 => 118959989688273472,
 6000000000000000000 => 142135049412622144,
 7000000000000000000 => 165220513980969424,
 8000000000000000000 => 188229829247429504,
 9000000000000000000 => 211172979243258278,
10000000000000000000 => 234057667276344607,
              524288 =>              43390,
             1048576 =>              82025,
             2097152 =>             155611,
             4194304 =>             295947,
             8388608 =>             564163,
            16777216 =>            1077871,
            33554432 =>            2063689,
            67108864 =>            3957809,
           134217728 =>            7603553,
           268435456 =>           14630843,
           536870912 =>           28192750,
          1073741824 =>           54400028,
          2147483648 =>          105097565,
          4294967296 =>          203280221,
          8589934592 =>          393615806,
         17179869184 =>          762939111,
         34359738368 =>         1480206279,
         68719476736 =>         2874398515,
        137438953472 =>         5586502348,
        274877906944 =>        10866266172,
        549755813888 =>        21151907950,
       1099511627776 =>        41203088796,
       2199023255552 =>        80316571436,
       4398046511104 =>       156661034233,
       8796093022208 =>       305761713237,
      17592186044416 =>       597116381732,
      35184372088832 =>      1166746786182,
      70368744177664 =>      2280998753949,
     140737488355328 =>      4461632979717,
     281474976710656 =>      8731188863470,
     562949953421312 =>     17094432576778,
    1125899906842624 =>     33483379603407,
    2251799813685248 =>     65612899915304,
    4503599627370496 =>    128625503610475,
    9007199254740992 =>    252252704148404,
   18014398509481984 =>    494890204904784,
   36028797018963968 =>    971269945245201,
   72057594037927936 =>   1906879381028850,
  144115188075855872 =>   3745011184713964,
  288230376151711744 =>   7357400267843990,
  576460752303423488 =>  14458792895301660,
 1152921504606846976 =>  28423094496953330,
 2305843009213693952 =>  55890484045084135,
 4611686018427387904 => 109932807585469973,
 9223372036854775808 => 216289611853439384,
# From http://trac.sagemath.org/ticket/7539 plus sieving
 11000000000000000000 => 256890014776557326,
 12000000000000000000 => 279675001309887227,
 13000000000000000000 => 302416755645383081,
 14000000000000000000 => 325118755759814408,
 15000000000000000000 => 347783970566657581,
 16000000000000000000 => 370414963651223281,
 17000000000000000000 => 393013970558176111,
 18000000000000000000 => 415582957615112220,
 18400000000000000000 => 424602543873663577,
 18440000000000000000 => 425504257754137607,
 18446700000000000000 => 425655290520421050,
 18446740000000000000 => 425656192205366999,
 18446744000000000000 => 425656282373661946,
 18446744030000000000 => 425656283049924141,
 18446744040000000000 => 425656283275356419,
 18446744050000000000 => 425656283500787632,
 18446744070000000000 => 425656283951611098,
 18446744073000000000 => 425656284019227775,
 18446744073700000000 => 425656284035002496,
 18446744073709000000 => 425656284035205391,
 18446744073709550000 => 425656284035217706,
 18446744073709551000 => 425656284035217730,
 18446744073709551615 => 425656284035217743,
);

use Math::BigInt try=>"GMP,Pari";
plan tests => 3*scalar(keys %pivals);

foreach my $n (sort {$a <=> $b} keys %pivals) {
  my $pin = $pivals{$n};
  $n = Math::BigInt->new($n) if $n > ~0;
  # stringify to work around Math::BigInt::GMP's stupid bug
  cmp_ok( ''.prime_count_upper($n), '>=', $pin, "Pi($n) <= upper estimate" );
  cmp_ok( ''.prime_count_lower($n), '<=', $pin, "Pi($n) >= lower estimate" );
  # Result may be bigint, so turn into float for percentage comparison
  my $approx = 0.0 + (''.prime_count_approx($n));
  my $percent_limit = ($n > 1000000000000) ? 0.00005
                    : ($n >   10000000000) ? 0.0002
                    : ($n >     100000000) ? 0.002
                    : ($n >       1000000) ? 0.02
                    : 0.2;
  cmp_ok( abs($pin - $approx) * (100.0 / $percent_limit), '<=', $pin, "prime_count_approx($n) within $percent_limit\% of Pi($n)");
}