Saya membutuhkan cara cepat untuk menghitung jumlah bit dalam integer dengan python. Solusi saya saat ini adalah
bin(n).count("1")
tetapi saya bertanya-tanya apakah ada cara yang lebih cepat untuk melakukan ini?
PS: (Saya mewakili array biner 2D besar sebagai satu daftar angka dan melakukan operasi bitwise, dan itu membawa waktu turun dari jam ke menit. Dan sekarang saya ingin membuang menit ekstra itu.
Edit: 1. harus di python 2.7 atau 2.6
dan mengoptimalkan angka kecil tidak terlalu menjadi masalah karena itu tidak akan menjadi hambatan yang jelas, tetapi saya memiliki angka dengan 10.000 + bit di beberapa tempat
misalnya ini adalah kasus 2000 bit:
12448057941136394342297748548545082997815840357634948550739612798732309975923280685245876950055614362283769710705811182976142803324242407017104841062064840113262840137625582646683068904149296501029754654149991842951570880471230098259905004533869130509989042199261339990315125973721454059973605358766253998615919997174542922163484086066438120268185904663422979603026066685824578356173882166747093246377302371176167843247359636030248569148734824287739046916641832890744168385253915508446422276378715722482359321205673933317512861336054835392844676749610712462818600179225635467147870208L
int
? Bukankah itu memiliki metode sendiri untuk menghitung ini?int.bit_length
seharusnya jawabannya, dan bukan yang diterima di bawah.Jawaban:
Untuk bilangan bulat dengan panjang arbitrer,
bin(n).count("1")
adalah yang tercepat yang dapat saya temukan di Python murni.Saya mencoba mengadaptasi solusi Óscar dan Adam untuk memproses integer masing-masing dalam potongan 64-bit dan 32-bit. Keduanya setidaknya sepuluh kali lebih lambat dari
bin(n).count("1")
(versi 32-bit membutuhkan waktu sekitar setengahnya lagi).Di sisi lain, gmpy
popcount()
memakan waktu sekitar 1/20 waktubin(n).count("1")
. Jadi, jika Anda dapat menginstal gmpy, gunakan itu.Untuk menjawab pertanyaan di komentar, untuk byte saya akan menggunakan tabel pencarian. Anda dapat membuatnya saat runtime:
Atau cukup definisikan secara harfiah:
Maka itu
counts[x]
untuk mendapatkan jumlah 1 bit dix
mana 0 ≤ x ≤ 255.sumber
bin(n).count("0")
tidak akurat karena awalan '0b'. Harusbin(n)[2:].count('0')
bagi mereka yang menghitung nakal ....numpy
array besar .bin(n).count("1")
. Namun, hanya mengalahkan 60% pengiriman python. @ leetcodeAnda dapat mengadaptasi algoritma berikut:
Ini berfungsi untuk bilangan positif 64-bit, tetapi mudah diperpanjang dan jumlah operasi bertambah dengan logaritma argumen (yaitu secara linier dengan ukuran bit argumen).
Untuk memahami cara kerjanya, bayangkan Anda membagi seluruh string 64-bit menjadi 64 keranjang 1-bit. Setiap nilai keranjang sama dengan jumlah bit yang disetel dalam keranjang (0 jika tidak ada bit yang disetel dan 1 jika satu bit disetel). Hasil transformasi pertama dalam keadaan analog, tetapi dengan 32 bucket masing-masing sepanjang 2-bit. Hal ini dicapai dengan menggeser bucket secara tepat dan menambahkan nilainya (satu penambahan akan menangani semua bucket karena tidak ada muatan yang dapat terjadi di seluruh bucket - nomor n-bit selalu cukup panjang untuk mengenkode angka n). Transformasi lebih lanjut menghasilkan status dengan jumlah bucket yang semakin berkurang secara eksponensial dengan ukuran yang tumbuh secara eksponensial hingga kami menemukan satu bucket dengan panjang 64-bit. Ini memberikan jumlah bit yang disetel dalam argumen asli.
sumber
CountBits()
untuk menangani angka 10k-bit dengan menambahkan hanya 8 baris kode. Tapi itu akan menjadi berat karena konstanta yang sangat besar.numpy
array besar .Berikut implementasi Python dari algoritma penghitungan populasi, seperti yang dijelaskan dalam posting ini :
Ini akan berhasil
0 <= i < 0x100000000
.sumber
bin(n).count("1")
.%timeit numberOfSetBits(23544235423)
:1000000 loops, best of 3: 818 ns per loop
;%timeit bitCountStr(23544235423)
:1000000 loops, best of 3: 577 ns per loop
.numberOfSetBits
proses saya 864 × 64numpy.ndarray
dalam 841 µs. DenganbitCountStr
saya harus melakukan loop secara eksplisit, dan dibutuhkan 40,7 ms, atau hampir 50 kali lebih lama.Menurut posting ini , ini tampaknya menjadi salah satu implementasi tercepat dari bobot Hamming (jika Anda tidak keberatan menggunakan memori sekitar 64KB).
Pada Python 2.x Anda harus mengganti
range
denganxrange
.Sunting
Jika Anda membutuhkan kinerja yang lebih baik (dan angka Anda adalah bilangan bulat besar), lihat
GMP
perpustakaan. Ini berisi implementasi perakitan tulisan tangan untuk banyak arsitektur yang berbeda.gmpy
adalah modul ekstensi Python berkode C yang membungkus pustaka GMP.sumber
array.array
forPOPCOUNT_TABLE16
, karena akan disimpan sebagai array bilangan bulat, bukan sebagai daftarint
objek Python yang berukuran dinamis .Saya sangat suka metode ini. Sederhana dan cukup cepat tetapi juga tidak terbatas dalam panjang bit karena python memiliki bilangan bulat tak terbatas.
Ini sebenarnya lebih licik daripada yang terlihat, karena menghindari membuang-buang waktu memindai nol. Misalnya, akan memakan waktu yang sama untuk menghitung bit yang ditetapkan dalam 1000000000000000000000010100000001 seperti pada 1111.
sumber
bin(n).count("1")
tetapi perlu 3,8 detik untuk fungsi Anda. Jika angkanya memiliki sedikit bit yang disetel, itu akan bekerja dengan cepat, tetapi jika Anda mengambil nomor acak apa pun, rata-rata fungsi di atas akan menjadi lipat lebih lambat.Anda dapat menggunakan algoritme untuk mendapatkan string biner [1] dari sebuah bilangan bulat tetapi alih-alih menggabungkan string, menghitung jumlah yang:
[1] https://wiki.python.org/moin/BitManipulation
sumber
Anda bilang Numpy terlalu lambat. Apakah Anda menggunakannya untuk menyimpan bit individual? Mengapa tidak memperluas gagasan menggunakan int sebagai larik bit tetapi menggunakan Numpy untuk menyimpannya?
Simpan n bit sebagai larik
ceil(n/32.)
int 32-bit. Anda kemudian dapat bekerja dengan numpy array dengan cara yang sama (baik, cukup mirip) seperti Anda menggunakan int, termasuk menggunakannya untuk mengindeks array lain.Algoritme ini pada dasarnya untuk menghitung, secara paralel, jumlah bit yang ditetapkan di setiap sel, dan menjumlahkan bitcount setiap sel.
Meskipun saya terkejut tidak ada yang menyarankan Anda menulis modul C.
sumber
sumber
Ternyata representasi awal Anda adalah daftar daftar int yang bisa 1 atau 0. Hitung saja dalam representasi itu.
Jumlah bit dalam integer konstan dalam python.
Namun, jika Anda ingin menghitung jumlah set bit, cara tercepat adalah membuat daftar yang sesuai dengan pseudocode berikut:
[numberofsetbits(n) for n in range(MAXINT)]
Ini akan memberi Anda pencarian waktu yang konstan setelah Anda membuat daftar. Lihat jawaban @ PaoloMoretti untuk implementasi yang baik dari ini. Tentu saja, Anda tidak harus menyimpan semua ini dalam memori - Anda dapat menggunakan semacam penyimpanan nilai kunci yang persisten, atau bahkan MySql. (Pilihan lain adalah menerapkan penyimpanan berbasis disk sederhana Anda sendiri).
sumber