| 
<?php
/******************************************************
 * Prime number checking and generation
 * @version 2.0
 * Adapted from:  Tzuly <[email protected]> v1.0
 * @author  cpks
 * @license Public Domain
 * @package prime
 */
 
 /**
 * Set of prime numbers
 *
 * Outputs:
 * - return whether a number is prime;
 * - construct a list of prime numbers;
 * - return biggest prime smaller than a number.
 *
 *************
 * Use:      *
 *************
 * - for finding if a number is prime: prime::is_prime($number);
 * - for biggest prime number smaller than x:
 *          prime::smallerPrime($x);
 * - for list of prime numbers smaller than x:
 *     $p = new prime($x);
 *   OR, using sieve of Eratosthenes:
 *     $e = new erato_prime($x);
 *   OR, using Atkin's sieve (a little slower):
 *     $a = new atkin_prime($x);
 *   OR, using sieve of Sundaram (uses half as much memory):
 *     $s = new sundaram_prime($x);
 * @package prime
 * @todo add an iterator to access the list and make primelist member private
 */
 class prime {
 /*
 * @var int[] array contains list of prime numbers
 */
 public $primelist = array();
 
 /**
 * return whether a number is prime
 *
 * @param int $number
 * @return boolean
 * @throws InvalidArgumentException
 */
 static public function is_prime($number) {
 if ($number < 2)
 throw new InvalidArgumentException('Prime numbers start at 2.');
 $number = (int)$number;
 for ($i = 2; $i < floor(sqrt($number) + 1); ++$i) {
 if (!($number % $i))
 return FALSE;
 }
 return TRUE;
 }
 /**
 * calculate biggest prime number smaller than $number
 *
 * @param int $number upper bound
 * @return int
 * @throws InvalidArgumentException
 */
 static public function smallerPrime($number) {
 if ($number <= 2)
 throw new InvalidArgumentException('2 is smallest prime number');
 
 for ($i = $number - 1; $i > 1; --$i)
 if (self::is_prime($i)) return $i;
 }
 
 /**
 * generate list of prime numbers, computed by calculating if every number
 * from list is prime
 *
 * @param int $number upper bound
 * @throws InvalidArgumentException
 */
 private function generate($number) {
 $this->primelist[] = 2;
 $this->primelist[] = 3;
 for ($i = 5; $i < $number; $i += 2) { // (BUG: was originally =+2)
 if (self::is_prime($i)) $this->primelist[] = $i;
 }
 }
 
 /**
 * Construct as a list of primes up to number supplied
 *
 * Use the generate method for the class
 * @param int $number upper bound
 * @throws InvalidArgumentException if upper bound < 3
 */
 public function __construct($number) {
 if ($number <= 2)
 throw new InvalidArgumentException('2 is smallest prime number');
 $this->generate($number);
 }
 
 /**
 * Compare with another instance
 * @param prime $other
 * @return bool TRUE if same
 */
 public function same_as(prime $other) {
 return $this->primelist == $other->primelist;
 }
 
 /**
 * Dump to stdout for debug purposes
 */
 public function dump() {
 echo implode(',', $this->primelist) . PHP_EOL;
 }
 }
 
 require_once 'bitvec.php';
 /**
 * Override generation to use the Eratosthenes sieve algorithm
 * @package prime
 */
 class erato_prime extends prime {
 /**
 * generate list of prime numbers, computed with Eratosthenes sieve algorithm
 *
 * @param int $number
 */
 private function generate($number) {
 $erat = new bitvec($number);
 $erat->setall();
 
 for ($i = 2; $i < $number; ++$i) {
 if ($erat[$i]) {
 for ($j = 2; $j * $i < $number; ++$j) $erat[$i * $j] = 0;
 }
 }
 for ($i = 2; $i < $number; ++$i) {
 if ($erat[$i]) $this->primelist[] = $i;
 }
 }
 }
 
 /**
 * Override generation to use the Atkin sieve algorithm
 * @package prime
 */
 class atkin_prime extends prime {
 /**
 * generate list of prime numbers, computed with atkin sieve algorithm
 *
 * @param int $number
 */
 private function generate($number) {
 $atkin = new bitvec($number);
 for ($i = 1; $i < sqrt($number); ++$i) {
 for ($j = 1; $j < sqrt($number); ++$j) {
 $x = 4 * $i * $i + $j * $j;
 if ($x < $number && ($x % 12 == 1 || $x % 12 == 5))
 $atkin[$x] = 1;
 
 $x = 3 * $i * $i + $j * $j;
 if ($x < $number && $x % 12 == 7)
 $atkin[$x] = 1;
 
 $x = 3 * $i * $i - $j * $j;
 if ($i > $j && $x < $number && $x % 12 == 11)
 $atkin[$x] = 1;
 }
 }
 for ($i = 5; $i < sqrt($number); ++$i) {
 $x = $i * $i;
 $j = 1;
 while ($j * $x < $number) {
 $atkin[$j * $x] = 0;
 ++$j;
 }
 }
 $atkin[2] = $atkin[3] = 1;
 for ($i = 2; $i < $number; ++$i) {
 if ($atkin[$i]) $this->primelist[] = $i;
 }
 }
 }
 
 /**
 * Override generation to use the Sundaram sieve algorithm
 * @package prime
 */
 class sundaram_prime extends prime {
 /**
 * generate list of prime numbers, computed with Sundaram sieve algorithm
 *
 * @param int $number
 */
 private function generate($number) {
 $number >>= 1;
 $sunda = new bitvec($number);
 $sunda->setall();
 for ($i = 1; $i < $number; ++$i) {
 $denominator = ($i << 1) + 1;
 $maxVal = ($number - $i) / $denominator;
 for ($j = $i; $j < $maxVal; ++$j) $sunda[$i + $j * $denominator] = 0;
 }
 $this->primelist[] = 2;
 for ($i = 1; $i < $number; ++$i) if ($sunda[$i]) $this->primelist[] = ($i << 1) + 1;
 }
 }
 
 |