[英]How to count prime number between 0 to 100000000 in less than 1 minute in PHP?
please help me to count prime number between 0 to 100000000 because I use to write but it works very slowly:请帮我计算 0 到 100000000 之间的质数,因为我曾经写过,但它工作得非常慢:
Here is my code:这是我的代码:
$n =100000000;
$answer =0;
for ($i = 2, $j = 2; $i <= $n; $i++) {
for ($j = 2; $j < $i; $j++) {
if ($i % $j == 0) {
break;
}
}
if ($j == $i) {
$answer++;
}
}
echo $answer . PHP_EOL;
Check out Sieve of Eratosthenes .检查埃拉托色尼筛。 This problem can be solved in less than 2 seconds on a modern desktop.
在现代桌面上,这个问题可以在不到 2 秒的时间内解决。 You can also try Bitwise Sieve which performs better in term of memory and speed.
您还可以尝试在内存和速度方面表现更好的Bitwise Sieve 。
As mentioned before use Sieve of Eratosthenes如前所述,使用埃拉托色尼筛
[4929.114 ms] find primes <= 100000000 found 5761456 primes
this is the source in C++:这是 C++ 中的源代码:
//---------------------------------------------------------------------------
int primes_found=0;
void addprime(int p)
{
// here do the stuff you want to do with prime p=2,3,5,7,...
// I just count the primes found ...
primes_found++;
}
//---------------------------------------------------------------------------
void getprimes(int p) // compute all primes up to p
{
// sieves N/16 bytes
// ------------------------------
// 0 1 2 3 4 5 6 7 bit
// ------------------------------
// 1 3 5 7 9 11 13 15 +-> +2
// 17 19 21 23 25 27 29 31 |
// 33 35 37 39 41 43 45 47 V +16
// ------------------------------
int N=(p|15),M=(N>>4)+1; // store only odd values 1,3,5,7,... each bit ...
char *m=new char[M]; // m[i] -> is 1+i+i prime? (factors map)
int i,j,k;
// init sieves
m[0]=254; for (i=1;i<M;i++) m[i]=255;
for(i=3;i<=N;i+=2)
for(k=i+i,j=i+k;j<=N;j+=k)
m[j>>4]&=255-(1<<((j>>1)&7));
// compute primes
addprime(2);
for(i=1,j=i>>4;j<M;i+=16,j++)
{
k=m[j];
if (!k) continue;
if (int(k& 1)!=0) addprime(i );
if (int(k& 2)!=0) addprime(i+ 2);
if (int(k& 4)!=0) addprime(i+ 4);
if (int(k& 8)!=0) addprime(i+ 6);
if (int(k& 16)!=0) addprime(i+ 8);
if (int(k& 32)!=0) addprime(i+10);
if (int(k& 64)!=0) addprime(i+12);
if (int(k&128)!=0) addprime(i+14);
}
delete[] m;
}
//---------------------------------------------------------------------------
#define addprime(prime) {...}
instead of function#define addprime(prime) {...}
代替函数 usage:用法:
getprimes(100000000);
[Notes] [笔记]
[edit1] init sieves by primes only [edit1] init 仅按素数筛选
// init sieves
m[0]=254; for (i=1;i<M;i++) m[i]=255;
for(i=1;i<=N;) // here could be also sqrt(N) instead of N (or half the bits number)
{
int a=m[i>>4];
if (int(a& 1)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 2)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 4)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 8)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 16)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 32)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a& 64)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
if (int(a&128)!=0) for(k=i+i,j=i+k;j<=N;j+=k) m[j>>4]&=255-(1<<((j>>1)&7)); i+=2;
}
[1520.160 ms] find primes <= 100000000 found 5761456 primes
Change the algorithm.改变算法。 Using Euler sieve.
使用欧拉筛。
this is my C++ code.这是我的 C++ 代码。 It will only cost 3 or 4 seconds.
它只需要 3 或 4 秒。
bool isprm[100000000+10];
int prm[5000000];
clr(isprm, true);
int cnt = 0;
for(int i=2; i<=n; i++)
{
if(isprm[i]) prm[++cnt] = i;
for(int j=1; j<=cnt && LL(i)*prm[j]<=n; j++)
{
isprm[ i*prm[j] ] = false;
if(i % prm[j] == 0) break;
}
}
skipping even numbers greater 2 and stopping at square root of i should give some speed up跳过大于 2 的偶数并停在 i 的平方根处应该可以加快速度
my c code:我的 C 代码:
int max = 100000000;
int i, j;
int answer = 0;
for(i=2;i<max;i++) {
if(i%2 == 0) continue;
for(j=3;j*j<i;j+=2) {
if(i%j == 0) break;
}
if(j*j >= i) answer++;
}
/*
PHP 7.3.7 x64
About 13~14 secs with AMD Ryzen 5 3600 (3,6Ghz)
*/
ini_set('memory_limit','2048M');
function countPrimes($n) {
$st = microtime(true);
$arr = new \SplFixedArray($n+1);
$cnt = 0;
for ($i=2;$i<=floor(sqrt($n));$i+=1) {
if (!isset($arr[$i])) {
for ($j=$i*2;$j<=$n;$j+=$i) {
if (!isset($arr[$j])) {
$arr[$j]=1;
$cnt++;
}
}
}
}
echo ($n-$cnt-1).' primes found from 0 to '.$n.' (in '.round((microtime(true) - $st),3).' secs)';
}
countPrimes(100000000);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.