Başbakan jeneratör optimizasyon

5 Cevap php

Project Euler içine gezimi başlıyorum. Ve diğerleri gibi ben bir asal sayı jeneratör yapmak gerekir düşündüm. Sorun: PHP büyük sayılar sevmez. Ben standart Sieve of Eratosthenes function kullanın ve 2 milyon sınırını ayarlarsanız, kilitlenmesine. O boyutta dizileri oluştururken sevmez. Anlaşılabilir.

Yani şimdi ben bunu optimize çalışıyorum. Bir yolu, buldum, bunun yerine, 2 milyon değişken ile bir dizi oluşturma, ben sadece 1 milyona ihtiyacım oldu (sadece tek sayıların asal sayılar olabilir). Bu maksimum yürütme süresini aştığından Ama şimdi çökmesini bulunuyor ...

function getPrimes($limit) {
$count = 0;
for ($i = 3; $i < $limit; $i += 2) {
	$primes[$count++] = $i;
}

for ($n = 3; $n < $limit; $n += 2) {
    //array will be half the size of $limit
	for ($i = 1; $i < $limit/2; $i++) {
		if ($primes[$i] % $n === 0 && $primes[$i] !== $n) {
			$primes[$i] = 0;
		}
	}
}

return $primes;
}

Işlevi çalışır, ama dediğim gibi, ... herhangi bir öneriniz biraz yavaş?

Biraz daha hızlı yapmak için bulduğum bir şey etrafında döngü geçmektir.

foreach ($primes as $value) {
    //$limitSq is the sqrt of the limit, as that is as high as I have to go
    for ($n = 3; $n = $limitSq; $n += 2) {
        if ($value !== $n && $value % $n === 0) {
            $primes[$count] = 0;
            $n = $limitSq; //breaking the inner loop
        }
    }
    $count++;
}

Ve zaman ve bellek sınırı (teşekkürler Greg) ayarı ek olarak, ben nihayet bir cevap almak başardınız. phjew.

5 Cevap

Dan Algorithmist's proposed solution

This is a modification of the standard Sieve of Eratosthenes. It would be highly inefficient, using up far too much memory and time, to run the standard sieve all the way up to n. However, no composite number less than or equal to n will have a factor greater than sqrt{n}, so we only need to know all primes up to this limit, which is no greater than 31622 (square root of 10^9). This is accomplished with a sieve. Then, for each query, we sieve through only the range given, using our pre-computed table of primes to eliminate composite numbers.

Bu sorun aynı zamanda UVA ait ve Sphere'in çevrimiçi hakimler üzerinde ortaya çıkmıştır. Here's how it's enunciated on Sphere.

Algoritması hakkında çok bilmeden:

  1. Sen $ i döngü etrafında $limit/2 her zaman hesaplamaya ediyoruz
  2. Sizin eğer deyimi sırayla değerlendirilir, bu nedenle $primes[$i] !== $n ilk test etmek için daha hızlı olacağını (ya da test) düşünmek olacaktır.

Yan not, set_time_limit() çalıştırmak için uzun vermek ve bunu kullanarak daha fazla bellek vermek için kullanabilirsiniz

ini_set('memory_limit', '128M');

Ayarlarınızı varsayarsak tabii, bu verir - kısıtlanmış olabilir paylaşılan bir bilgisayar üzerinde.

Sen elek saklamak için biraz alanı kullanabilirsiniz. Bu büyük bir tamsayı içine booleans paketi dışında o, booleans bir dizi kabaca aynıdır bulunuyor vardır. Eğer 8-bitlik tamsayılar olsaydı Örneğin size daha da alan gereksinimini azaltacak tamsayı başına 8 bit (booleans) saklamak istiyorsunuz.

Ayrıca, bir bit alanını kullanarak elek işlemi gerçekleştirmek için bit maskeleri kullanma imkanı sağlar. Lütfen elek Tüm numaraları (sadece tek olanları) muhafaza Örneğin, sen b01010101 biraz maskesi oluşturmak hangi sonra VE sizin dizideki her elemanın karşı olabilir. B00100100 b10010010 b01001001: üçerli için, maske olarak üç tamsayılar kullanabilirsiniz.

Son olarak, $n, aslında sen $n*$n-1 daha az numaraları kontrol etmek gerekmez daha düşük numaralarını kontrol etmek gerekmez.

Eğer sayı bir asal değildir biliyorum, ben döngüye girmek çıkmak olacak. Ben php bilmiyorum, ama sen C bir mola veya Perl bir son gibi bir açıklama gerekiyor.

Bu mevcut değilse, ben bir bayrak ve interloop devam eden bir koşulu olarak arası döngü çıkmak için kullanmak istiyorsunuz. Bir asal değilse $ limit / 2 öğe kontrol etmiyor gibi bu yürütme hızlandırmak gerekir.

hız istiyorsanız, bu bir PHP kullanmayın: P

hayır, cidden, gerçekten PHP gibi ben ve serin bir dil olduğunu, ancak bu tür algoritmalar için hiç uygun değil