Ich brauche einen schnellen Weg, um die Anzahl der Bits in einer Ganzzahl in Python zu zählen. Meine aktuelle Lösung ist
bin(n).count("1")
aber ich frage mich, ob es einen schnelleren Weg gibt, dies zu tun?
PS: (Ich stelle ein großes 2D-Binärarray als einzelne Liste von Zahlen dar und führe bitweise Operationen durch. Dadurch wird die Zeit von Stunden auf Minuten verkürzt. Jetzt möchte ich diese zusätzlichen Minuten loswerden.
Bearbeiten: 1. Es muss in Python 2.7 oder 2.6 sein
und die Optimierung für kleine Zahlen spielt keine große Rolle, da dies kein klarer Engpass wäre, aber ich habe an einigen Stellen Zahlen mit mehr als 10 000 Bits
Dies ist beispielsweise ein 2000-Bit-Fall:
12448057941136394342297748548545082997815840357634948550739612798732309975923280685245876950055614362283769710705811182976142803324242407017104841062064840113262840137625582646683068904149296501029754654149991842951570880471230098259905004533869130509989042199261339990315125973721454059973605358766253998615919997174542922163484086066438120268185904663422979603026066685824578356173882166747093246377302371176167843247359636030248569148734824287739046916641832890744168385253915508446422276378715722482359321205673933317512861336054835392844676749610712462818600179225635467147870208L
int
? Hat das nicht eine eigene Methode, um dies zu berechnen?int.bit_length
sollte die Antwort sein und nicht die unten akzeptierte.Antworten:
Für Ganzzahlen beliebiger Länge
bin(n).count("1")
ist dies die schnellste, die ich in reinem Python finden konnte.Ich habe versucht, die Lösungen von Óscar und Adam so anzupassen, dass die Ganzzahl in 64-Bit- bzw. 32-Bit-Blöcken verarbeitet wird. Beide waren mindestens zehnmal langsamer als
bin(n).count("1")
(die 32-Bit-Version brauchte wieder etwa halb so viel Zeit).Auf der anderen Seite dauerte gmpy
popcount()
ungefähr 1/20 der Zeit vonbin(n).count("1")
. Wenn Sie also gmpy installieren können, verwenden Sie das.Um eine Frage in den Kommentaren zu beantworten, würde ich für Bytes eine Nachschlagetabelle verwenden. Sie können es zur Laufzeit generieren:
Oder definieren Sie es einfach wörtlich:
Dann ist es
counts[x]
, die Anzahl von 1 Bits zu erhalten,x
wobei 0 ≤ x ≤ 255 ist.quelle
bin(n).count("0")
ist aufgrund des Präfixes '0b' nicht genau. Müsstebin(n)[2:].count('0')
für diejenigen sein, die Naughts zählen ...numpy
Arrays ausgeführt werden.bin(n).count("1")
. Schlägt jedoch nur 60% der Python-Einreichung. @ LeetcodeSie können den folgenden Algorithmus anpassen:
Dies funktioniert für positive 64-Bit-Zahlen, ist jedoch leicht erweiterbar und die Anzahl der Operationen wächst mit dem Logarithmus des Arguments (dh linear mit der Bitgröße des Arguments).
Um zu verstehen, wie dies funktioniert, stellen Sie sich vor, Sie teilen die gesamte 64-Bit-Zeichenfolge in 64 1-Bit-Buckets. Der Wert jedes Buckets entspricht der Anzahl der im Bucket gesetzten Bits (0, wenn keine Bits gesetzt sind, und 1, wenn ein Bit gesetzt ist). Die erste Transformation führt zu einem analogen Zustand, jedoch mit 32 Buckets von jeweils 2 Bit Länge. Dies wird erreicht, indem die Buckets entsprechend verschoben und ihre Werte addiert werden (eine Addition kümmert sich um alle Buckets, da kein Übertrag zwischen Buckets auftreten kann - die n-Bit-Nummer ist immer lang genug, um die Nummer n zu codieren). Weitere Transformationen führen zu Zuständen mit exponentiell abnehmender Anzahl von Buckets exponentiell wachsender Größe, bis wir zu einem 64 Bit langen Bucket gelangen. Dies gibt die Anzahl der im ursprünglichen Argument gesetzten Bits an.
quelle
CountBits()
10k-Bit-Zahlen neu schreiben , indem Sie nur 8 Codezeilen hinzufügen. Aber es wird aufgrund großer Konstanten unhandlich.numpy
.Hier ist eine Python-Implementierung des Populationszählalgorithmus, wie in diesem Beitrag erläutert :
Es wird funktionieren für
0 <= i < 0x100000000
.quelle
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
verarbeitet meine 864 × 64numpy.ndarray
in 841 & mgr; s. Mit mussbitCountStr
ich explizit schleifen, und es dauert 40,7 ms oder fast 50 mal länger.Laut diesem Beitrag scheint dies eine der schnellsten Implementierungen des Hamming-Gewichts zu sein (wenn es Ihnen nichts ausmacht, etwa 64 KB Speicher zu verwenden).
Auf Python 2.x Sie ersetzen sollten
range
mitxrange
.Bearbeiten
Wenn Sie eine bessere Leistung benötigen (und Ihre Zahlen große Zahlen sind), schauen Sie sich die
GMP
Bibliothek an. Es enthält handgeschriebene Assembly-Implementierungen für viele verschiedene Architekturen.gmpy
ist ein C-codiertes Python-Erweiterungsmodul, das die GMP-Bibliothek umschließt.quelle
array.array
für verwendenPOPCOUNT_TABLE16
, da sie dann als Array von Ganzzahlen und nicht als dynamisch dimensionierte Liste von Python-int
Objekten gespeichert wird .Ich mag diese Methode wirklich. Es ist einfach und ziemlich schnell, aber auch nicht in der Bitlänge begrenzt, da Python unendlich viele ganze Zahlen hat.
Es ist tatsächlich schlauer als es aussieht, weil es keine Zeit damit verschwendet, die Nullen zu scannen. Beispielsweise dauert das Zählen der gesetzten Bits in 1000000000000000000000010100000001 genauso lange wie in 1111.
quelle
bin(n).count("1")
Sekunden, für Ihre Funktion jedoch 3,8 Sekunden. Wenn für die Zahlen nur sehr wenige Bits gesetzt wären, würde dies schnell funktionieren. Wenn Sie jedoch eine Zufallszahl verwenden, ist die obige Funktion im Durchschnitt um Größenordnungen langsamer.Sie können den Algorithmus verwenden, um die Binärzeichenfolge [1] einer Ganzzahl abzurufen, aber anstatt die Zeichenfolge zu verketten, zählen Sie die Anzahl der Einsen:
[1] https://wiki.python.org/moin/BitManipulation
quelle
Sie sagten, Numpy sei zu langsam. Haben Sie es verwendet, um einzelne Bits zu speichern? Warum nicht die Idee erweitern, Ints als Bit-Arrays zu verwenden, sondern diese mit Numpy speichern?
Speichern Sie n Bits als Array von
ceil(n/32.)
32-Bit-Ints. Sie können dann mit dem numpy-Array auf die gleiche (gut genug ähnliche) Weise arbeiten, wie Sie Ints verwenden, einschließlich der Verwendung, um ein anderes Array zu indizieren.Der Algorithmus besteht im Wesentlichen darin, parallel die Anzahl der in jeder Zelle gesetzten Bits zu berechnen und die Bitanzahl jeder Zelle zusammenzufassen.
Obwohl ich überrascht bin, hat niemand vorgeschlagen, ein C-Modul zu schreiben.
quelle
quelle
Es stellt sich heraus, dass Ihre Startdarstellung eine Liste von Ints-Listen ist, die entweder 1 oder 0 sind. Zählen Sie sie einfach in dieser Darstellung.
Die Anzahl der Bits in einer Ganzzahl ist in Python konstant.
Wenn Sie jedoch die Anzahl der gesetzten Bits zählen möchten, erstellen Sie am schnellsten eine Liste, die dem folgenden Pseudocode entspricht:
[numberofsetbits(n) for n in range(MAXINT)]
Dadurch erhalten Sie eine konstante Zeitsuche, nachdem Sie die Liste erstellt haben. Eine gute Implementierung finden Sie in der Antwort von @ PaoloMoretti. Natürlich müssen Sie dies nicht alles im Speicher behalten - Sie könnten einen dauerhaften Schlüsselwertspeicher oder sogar MySQL verwenden. (Eine andere Möglichkeit wäre, einen eigenen einfachen festplattenbasierten Speicher zu implementieren.)
quelle