Skip to content

Instantly share code, notes, and snippets.

@drupol
Last active August 27, 2020 21:07
Show Gist options
  • Save drupol/e43dd8e02da56fc3013a4e37ee3749d9 to your computer and use it in GitHub Desktop.
Save drupol/e43dd8e02da56fc3013a4e37ee3749d9 to your computer and use it in GitHub Desktop.
Finding primes in PHP with a lazy collection library.
<?php
/**
* @file
* Example/demo file.
*
* @see https://github.com/loophp/collection
*/
declare(strict_types=1);
include 'vendor/autoload.php';
use loophp\collection\Collection;
use function in_array;
use const INF;
/**
* Get the divisor of a given number.
*
* @param float $num
* The number.
* @param int $start
* The start.
*
* @return \Traversable
* The divisors of the number.
*/
function factors(float $num, int $start = 1): Traversable
{
if (0 === $num % $start) {
yield $start => $start;
yield $num / $start => $num / $start;
}
if (ceil(sqrt($num)) >= $start) {
yield from factors($num, $start + 1);
}
}
/**
* Check if a number is a multiple of 2.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number is a multiple of 2.
*/
$notMultipleOf2 = static function ($value): bool {
return 0 !== $value % 2;
};
/**
* Check if a number is a multiple of 3.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number is a multiple of 3.
*/
$notMultipleOf3 = static function ($value): bool {
$sumIntegers = static function ($value): float {
return array_reduce(
mb_str_split((string) $value),
static function ($carry, $value) {
return $value + $carry;
},
0
);
};
$sum = $sumIntegers($value);
while (10 < $sum) {
$sum = $sumIntegers($sum);
}
return 0 !== $sum % 3;
};
/**
* Check if a number is a multiple of 5.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number is a multiple of 5.
*/
$notMultipleOf5 = static function ($value): bool {
return !in_array(mb_substr((string) $value, -1), ['0', '5'], true);
};
/**
* Check if a number is a multiple of 7.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number is a multiple of 7.
*/
$notMultipleOf7 = static function ($value): bool {
$number = $value;
while (14 <= $number) {
$lastDigit = mb_substr((string) $number, -1);
if ('0' === $lastDigit) {
return true;
}
$number = (int) abs((int) mb_substr((string) $number, 0, -1) - 2 * (int) $lastDigit);
}
return !(0 === $number || 7 === $number);
};
/**
* Check if a number is a multiple of 11.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number is a multiple of 11.
*/
$notMultipleOf11 = static function ($value): bool {
$number = $value;
while (11 < $number) {
$lastDigit = mb_substr((string) $number, -1);
if ('0' === $lastDigit) {
return true;
}
$number = (int) abs((int) mb_substr((string) $number, 0, -1) - (int) $lastDigit);
}
return !(0 === $number || 11 === $number);
};
/**
* Check if a number have more than 2 divisors.
*
* @param $value
* The number.
*
* @return bool
* Whether or not the number has more than 2 divisors.
*/
$valueHavingMoreThan2Divisors = static function ($value): bool {
$i = 0;
foreach (factors($value) as $factor) {
if (2 < $i++) {
return false;
}
}
return true;
};
$start = microtime(true);
$primes = Collection::range(9, INF, 2) // Count from 10 to infinity
->filter($notMultipleOf2) // Filter out multiples of 2
->filter($notMultipleOf3) // Filter out multiples of 3
->filter($notMultipleOf5) // Filter out multiples of 5
->filter($notMultipleOf7) // Filter out multiples of 7
->filter($notMultipleOf11) // Filter out multiples of 11
->filter($valueHavingMoreThan2Divisors) // Filter out values having more than 2 divisors.
->prepend(2, 3, 5, 7) // Add back digits that were removed
->normalize() // Re-index the keys
->limit(100); // Take the 100 first prime numbers.
print_r($primes->all());
$time = microtime(true) - $start;
var_dump($time);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment