Ini adalah algoritma terbaik yang bisa saya kemukakan.
def get_primes(n):
numbers = set(range(n, 1, -1))
primes = []
while numbers:
p = numbers.pop()
primes.append(p)
numbers.difference_update(set(range(p*2, n+1, p)))
return primes
>>> timeit.Timer(stmt='get_primes.get_primes(1000000)', setup='import get_primes').timeit(1)
1.1499958793645562
Bisakah itu dibuat lebih cepat?
Kode ini memiliki kekurangan: Karena numbers
merupakan kumpulan yang tidak berurutan, tidak ada jaminan yang numbers.pop()
akan menghapus angka terendah dari kumpulan tersebut. Namun demikian, ini berfungsi (setidaknya bagi saya) untuk beberapa nomor input:
>>> sum(get_primes(2000000))
142913828922L
#That's the correct sum of all numbers below 2 million
>>> 529 in get_primes(1000)
False
>>> 529 in get_primes(530)
True
python
math
optimization
primes
jbochi
sumber
sumber
import antigravity
. Apakah tidak ada yang sepertirequire 'prime'; Prime.take(10)
(Ruby)?Jawaban:
Peringatan:
timeit
hasil dapat bervariasi karena perbedaan perangkat keras atau versi Python.Di bawah ini adalah skrip yang membandingkan sejumlah implementasi:
Banyak terima kasih kepada stephan karena telah membawa sieve_wheel_30 menjadi perhatian saya. Penghargaan diberikan kepada Robert William Hanks untuk primesfrom2to, primesfrom3to, rwh_primes, rwh_primes1, dan rwh_primes2.
Dari metode Python biasa diuji, dengan psyco , untuk n = 1000000, rwh_primes1 adalah yang tercepat diuji.
Dari metode Python biasa yang diuji, tanpa psyco , untuk n = 1000000, rwh_primes2 adalah yang tercepat.
Dari semua metode yang diuji, memungkinkan numpy , untuk n = 1000000, primesfrom2to adalah yang tercepat diuji.
Pengaturan waktu diukur menggunakan perintah:
dengan
{method}
diganti oleh masing-masing nama metode.primes.py:
Menjalankan tes skrip yang semua implementasi memberikan hasil yang sama.
sumber
gmpy
- ia memiliki dukungan yang cukup bagus untuk bilangan prima, melaluinext_prime
metodempz
jenisnya.Kode Python murni yang lebih cepat & lebih bijaksana:
atau mulai dengan setengah saringan
Kode numpy lebih cepat & lebih bijaksana untuk memori:
variasi yang lebih cepat dimulai dengan sepertiga ayakan:
Versi python murni (sulit-kode) dari kode di atas adalah:
Sayangnya pure-python tidak mengadopsi cara numpy yang lebih sederhana dan cepat dalam melakukan penugasan, dan memanggil
len()
di dalam loop karena[False]*len(sieve[((k*k)//3)::2*k])
terlalu lambat. Jadi saya harus berimprovisasi untuk mengoreksi input (& menghindari lebih banyak matematika) dan melakukan beberapa sihir matematika yang ekstrim (& menyakitkan).Secara pribadi saya pikir itu memalukan bahwa numpy (yang begitu banyak digunakan) bukan bagian dari pustaka standar Python, dan bahwa perbaikan dalam sintaks dan kecepatan tampaknya sepenuhnya diabaikan oleh pengembang Python.
sumber
bitarray
- seperti yang digunakan di sini (untuk saringan utama yang paling sederhana; bukan pesaing dalam lomba di sini!) stackoverflow.com/questions/31120986/...primesfrom2to()
metode, haruskah pembagian berada di dalam kurung?Ada contoh yang cukup rapi dari Python Cookbook di sini - versi tercepat yang diajukan pada URL itu adalah:
jadi itu akan memberi
Mengukur pada prompt shell (seperti yang saya suka lakukan) dengan kode ini di pri.py, saya perhatikan:
jadi sepertinya solusi Cookbook lebih dari dua kali lebih cepat.
sumber
Dengan menggunakan Saringan Sundaram , saya pikir saya memecahkan rekor Python murni:
Perbandingan:
sumber
None
alih-alih fungsi asli berfungsi dan itu bahkan lebih cepat daripadazero.__sub__
sundaram3(9)
akan kembali[2, 3, 5, 7, 9]
? Tampaknya melakukan ini dengan banyak - mungkin semua - angka ganjil (bahkan ketika mereka tidak prima)Algoritma ini cepat, tetapi memiliki kelemahan serius:
Anda menganggap bahwa
numbers.pop()
akan mengembalikan angka terkecil di set, tetapi ini tidak dijamin sama sekali. Set tidak berurutan danpop()
menghapus serta mengembalikan elemen arbitrer , sehingga tidak dapat digunakan untuk memilih prime berikutnya dari angka yang tersisa.sumber
Untuk benar-benar solusi tercepat dengan N cukup besar akan men-download daftar pra-dihitung dari bilangan prima , menyimpannya sebagai tupel dan melakukan sesuatu seperti:
Jika
N > primes[-1]
hanya kemudian menghitung lebih banyak bilangan prima dan menyimpan daftar baru dalam kode Anda, jadi lain kali sama cepatnya.Selalu berpikir di luar kotak.
sumber
Jika Anda tidak ingin menemukan kembali roda, Anda dapat menginstal sympy library simbolik matematika (ya itu kompatibel dengan Python 3)
Dan gunakan fungsi primerange
sumber
Jika Anda menerima itertools tetapi tidak numpy, ini adalah adaptasi dari rwh_primes2 untuk Python 3 yang berjalan sekitar dua kali lebih cepat di komputer saya. Satu-satunya perubahan substansial adalah menggunakan bytearray alih-alih daftar untuk boolean, dan menggunakan kompres alih-alih pemahaman daftar untuk membangun daftar akhir. (Saya akan menambahkan ini sebagai komentar seperti moarningsun jika saya bisa.)
Perbandingan:
dan
sumber
Sangat membantu untuk menulis kode penemuan utama Anda sendiri, tetapi juga bermanfaat untuk memiliki perpustakaan yang andal dan cepat. Saya menulis pembungkus di sekitar C ++ library primesieve , menamainya primesieve-python
Cobalah
pip install primesieve
Saya ingin tahu melihat kecepatan dibandingkan.
sumber
count_primes
fungsinya jauh lebih cepat daripadagenerate_primes
Berikut adalah dua versi yang diperbarui (pure Python 3.6) dari salah satu fungsi tercepat,
sumber
Implementasi deterministik dari uji Primality Miller-Rabin dengan asumsi bahwa N <9.080.191
Menurut artikel di Wikipedia ( http://en.wikipedia.org/wiki/Miller–Rabin_primality_test ) menguji N <9.080.191 untuk a = 2,3,37, dan 73 sudah cukup untuk memutuskan apakah N adalah komposit atau tidak.
Dan saya mengadaptasi kode sumber dari implementasi probabilistik uji Miller-Rabin asli yang ditemukan di sini: http://en.literateprograms.org/Miller-Rabin_primality_test_(Python)
sumber
Jika Anda memiliki kendali atas N, cara paling cepat untuk membuat daftar semua bilangan prima adalah dengan melakukannya. Serius. Precomputing adalah cara optimasi yang terlewatkan.
sumber
Berikut kode yang biasanya saya gunakan untuk menghasilkan bilangan prima dengan Python:
Itu tidak dapat bersaing dengan solusi lebih cepat yang diposting di sini, tetapi setidaknya itu adalah python murni.
Terima kasih telah mengirimkan pertanyaan ini. Saya benar-benar belajar banyak hari ini.
sumber
Untuk kode tercepat, solusi numpy adalah yang terbaik. Untuk alasan akademis murni, saya memposting versi python murni saya, yang sedikit kurang dari 50% lebih cepat dari versi buku resep yang diposting di atas. Karena saya membuat seluruh daftar dalam memori, Anda membutuhkan ruang yang cukup untuk menampung semuanya, tetapi tampaknya skalanya cukup baik.
Dan hasilnya:
sumber
Implementasi yang sedikit berbeda dari saringan setengah menggunakan Numpy:
http://rebrained.com/?p=458
Bisakah seseorang membandingkan ini dengan timing lainnya? Di komputer saya sepertinya cukup sebanding dengan setengah-saringan Numpy lainnya.
sumber
upto=10**6
:primesfrom2to()
- 7 ms;prime6()
- 12 ms ideone.com/oDg2YSemuanya ditulis dan diuji. Jadi tidak perlu menemukan kembali roda.
memberi kami pemecahan rekor 12.2 msec !
Jika ini tidak cukup cepat, Anda dapat mencoba PyPy:
yang mengakibatkan:
Jawaban dengan 247 daftar suara mendaftar 15,9 ms untuk solusi terbaik. Bandingkan ini !!!
sumber
Saya menguji beberapa fungsi unutbu , saya menghitungnya dengan angka jutaan hungred
Pemenangnya adalah fungsi yang menggunakan perpustakaan numpy,
Catatan : Ini juga akan menarik untuk melakukan tes pemanfaatan memori :)
Kode sampel
Kode lengkap di repositori github saya
sumber
Untuk Python 3
sumber
Saringan perdana tercepat di Pure Python :
Saya dioptimalkan Saringan Eratosthenes untuk kecepatan dan memori.
Tolok ukur
Keluaran
sumber
Pertama kali menggunakan python, jadi beberapa metode yang saya gunakan dalam hal ini mungkin terlihat sedikit rumit. Saya langsung mengkonversikan kode c ++ saya ke python dan inilah yang saya miliki (walaupun sedikit lambat di python)
sumber
Saya tahu kompetisi ditutup selama beberapa tahun. ...
Meskipun demikian ini adalah saran saya untuk saringan prime python murni, berdasarkan menghilangkan kelipatan 2, 3 dan 5 dengan menggunakan langkah-langkah yang tepat saat memproses ayakan maju. Meskipun demikian sebenarnya lebih lambat untuk N <10 ^ 9 daripada @Robert William Hanks solusi superior rwh_primes2 dan rwh_primes1. Dengan menggunakan array saringan ctypes.c_ushort di atas 1,5 * 10 ^ 8 itu entah bagaimana adaptif dengan batas memori.
10 ^ 6
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000)" 10 loop, terbaik 3: 46,7 msec per loop
10 ^ 7
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (10000000)" 10 loop, terbaik 3: 530 msec per loop
10 ^ 8
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (100000000)" 10 loop, terbaik 3: 5,55 detik per loop
10 ^ 9
$ python -mtimeit -s "import primeSieveSpeedComp" "primeSieveSpeedComp.primeSieveSeq (1000000000)" 10 loop, terbaik 3: 61,2 detik per loop
Anda dapat menyalin kode di bawah ini ke ubuntus primeSieveSpeedComp untuk meninjau tes ini.
sumber
Berikut ini adalah versi Saringan Eratosthenes yang numpy yang memiliki kompleksitas yang baik (lebih rendah daripada menyortir array dengan panjang n) dan vektorisasi. Dibandingkan dengan @unutbu kali ini secepat paket dengan 46 mikron untuk menemukan semua bilangan prima di bawah satu juta.
Pengaturan waktu:
sumber
Saya telah memperbarui banyak kode untuk Python 3 dan melemparkannya di perfplot (proyek saya) untuk melihat mana yang sebenarnya tercepat. Ternyata, untuk yang besar
n
,primesfrom{2,3}to
ambil kue:Kode untuk mereproduksi plot:
sumber
Dugaan saya adalah bahwa yang tercepat dari semua cara adalah dengan mengkodekan bilangan prima dalam kode Anda.
Jadi mengapa tidak hanya menulis skrip lambat yang menghasilkan file sumber lain yang memiliki semua angka yang tertanam di dalamnya, dan kemudian mengimpor file sumber itu ketika Anda menjalankan program Anda yang sebenarnya.
Tentu saja, ini bekerja hanya jika Anda tahu batas atas N pada waktu kompilasi, tetapi demikian halnya untuk (hampir) semua masalah Euler proyek.
PS: Saya mungkin salah meskipun jika menguraikan sumber dengan bilangan prima terprogram lebih lambat daripada menghitungnya, tetapi sejauh yang saya tahu Python menjalankan dari
.pyc
file yang dikompilasi sehingga membaca array biner dengan semua bilangan prima hingga N harus berdarah cepat dalam hal itu.sumber
Maaf mengganggu tapi erat2 () memiliki kesalahan serius dalam algoritma.
Saat mencari komposit berikutnya, kita perlu menguji angka ganjil saja. q, p keduanya aneh; maka q + p adalah genap dan tidak perlu diuji, tetapi q + 2 * p selalu aneh. Ini menghilangkan tes "jika genap" dalam kondisi loop sementara dan menyimpan sekitar 30% dari runtime.
Sementara kita melakukannya: alih-alih elegan 'D.pop (q, None)' dapatkan dan hapus metode gunakan 'jika q dalam D: p = D [q], del D [q]' yang dua kali lebih cepat ! Setidaknya di mesin saya (P3-1Ghz). Jadi saya sarankan implementasi algoritma pintar ini:
sumber
Metode tercepat yang saya coba sejauh ini didasarkan pada fungsi buku resep Python
erat2
:Lihat jawaban ini untuk penjelasan tentang percepatan.
sumber
Saya mungkin terlambat ke pesta tetapi harus menambahkan kode saya sendiri untuk ini. Ini menggunakan sekitar n / 2 di ruang karena kita tidak perlu menyimpan angka genap dan saya juga menggunakan modul bitarray python, lebih jauh mengurangi konsumsi memori dan memungkinkan komputasi semua prima hingga 1.000.000.000
Ini dijalankan pada 64bit 2.4GHZ MAC OSX 10.8.3
sumber
Saya mengumpulkan beberapa saringan bilangan prima dari waktu ke waktu. Yang tercepat di komputer saya adalah ini:
sumber
Saya lambat menanggapi pertanyaan ini tetapi sepertinya latihan yang menyenangkan. Saya menggunakan numpy yang mungkin curang dan saya ragu metode ini adalah yang tercepat tetapi harus jelas. Ini menyaring array Boolean mengacu hanya pada indeksnya dan memunculkan bilangan prima dari indeks semua nilai True. Tidak perlu modulo.
sumber
ajs_primes3a(10)
->array([2, 3, 5, 7, 9])
.9
bukan primenumpy
solusi berbasis yang mengembalikan array. Catatan: tidak benar implementasi Saringan Eratosthenes menggunakan modulo - tidak perlu menyebutkannya. Anda bisa menggunakanmat[idx*idx::idx]
bukanmat[idx*2::idx]
. Dannp.nonzero(mat)[0]
bukannyanp.where(mat == True)[0]
.Berikut adalah teknik yang menarik untuk menghasilkan bilangan prima (namun bukan yang paling efisien) menggunakan pemahaman daftar python:
Anda dapat menemukan contoh dan beberapa penjelasan di sini
sumber