Ich brauche eine Funktion wie diese:
// return true iff 'n' is a power of 2, e.g.
// is_power_of_2(16) => true is_power_of_2(3) => false
bool is_power_of_2(int n);
Kann mir jemand vorschlagen, wie ich das schreiben könnte? Können Sie mir eine gute Website nennen, auf der diese Art von Algorithmus zu finden ist?
c++
algorithm
bit-manipulation
Ameise
quelle
quelle
Antworten:
(n & (n - 1)) == 0
ist das Beste. Beachten Sie jedoch, dass für n = 0 fälschlicherweise true zurückgegeben wird. Wenn dies möglich ist, sollten Sie dies explizit überprüfen.http://www.graphics.stanford.edu/~seander/bithacks.html verfügt über eine große Sammlung cleverer Bit-Twiddling-Algorithmen, einschließlich dieses.
quelle
(n>0 && ((n & (n-1)) == 0))
n && !(n & (n - 1))
als Link innerhalb der Antwort angegeben.n & !(n & (n - 1))
. Beachten Sie das bitweise UND&
(nicht logisch und&&
). Bitweise Operatoren implementieren keinen Kurzschluss und daher verzweigt der Code nicht. Dies ist in Situationen vorzuziehen, in denen Zweigfehlvorhersagen wahrscheinlich sind und wenn die Berechnung der Rhs des Ausdrucks (dh!(n & (n - 1))
) billig ist.!
ist ein logischer Operator und daher wäre der Wert von!(n & (n - 1))
ein Boolescher Wert. Sind Sie sicher, dass einem bitweisen UND-Operator ein Boolescher Wert und eine Zahl zugewiesen werden können? Wenn ja, sieht es gut aus.Bei einer Zweierpotenz wird nur ein Bit gesetzt (für vorzeichenlose Zahlen). Etwas wie
Wird gut funktionieren; Eins weniger als eine Zweierpotenz ist alles 1s in den weniger signifikanten Bits, muss also bitweise UND auf 0 sein.
Da ich vorzeichenlose Zahlen angenommen habe, ist der == 0-Test (den ich ursprünglich vergessen habe, sorry) ausreichend. Möglicherweise möchten Sie einen Test> 0, wenn Sie vorzeichenbehaftete Ganzzahlen verwenden.
quelle
Zweierpotenzen in Binärform sehen folgendermaßen aus:
Beachten Sie, dass immer genau 1 Bit gesetzt ist. Die einzige Ausnahme ist eine vorzeichenbehaftete Ganzzahl. Beispiel: Eine 8-Bit-Ganzzahl mit Vorzeichen und einem Wert von -128 sieht folgendermaßen aus:
Nachdem wir überprüft haben, ob die Zahl größer als Null ist, können wir mit einem cleveren kleinen Bit-Hack testen, ob nur ein Bit gesetzt ist.
Weitere Informationen finden Sie hier .
quelle
Ansatz 1:
Teilen Sie die Zahl ausschließlich durch 2, um sie zu überprüfen.
Zeitliche Komplexität: O (log2n).
Ansatz 2:
Bitweise UND die Zahl mit der gerade vorherigen Zahl sollte gleich NULL sein.
Beispiel: Zahl = 8 Binär von 8: 1 0 0 0 Binär von 7: 0 1 1 1 und das bitweise UND beider Zahlen ist 0 0 0 0 = 0.
Zeitliche Komplexität: O (1).
Ansatz 3:
Bitweises XOR Die Zahl mit der gerade vorherigen Zahl sollte die Summe beider Zahlen sein.
Beispiel: Zahl = 8 Binär von 8: 1 0 0 0 Binär von 7: 0 1 1 1 und das bitweise XOR beider Zahlen ist 1 1 1 1 = 15.
Zeitliche Komplexität: O (1).
http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html
quelle
quelle
Für jede Potenz von 2 gilt auch das Folgende.
n & (- n) == n
HINWEIS: Die Bedingung gilt für n = 0, obwohl es keine Potenz von 2 ist.
Grund dafür ist:
-n ist das 2s-Komplement von n. -n wird jedes Bit links vom am weitesten rechts gesetzten Bit von n im Vergleich zu n umgedreht haben. Für Potenzen von 2 gibt es nur ein gesetztes Bit.
quelle
In C ++ 20 gibt es eine,
std::ispow2
die Sie genau für diesen Zweck verwenden können, wenn Sie sie nicht selbst implementieren müssen:quelle
Dies ist wahrscheinlich die schnellste, wenn Sie GCC verwenden. Es wird nur eine POPCNT-CPU-Anweisung und ein Vergleich verwendet. Bei der binären Darstellung einer Potenz mit 2 Zahlen wird immer nur ein Bit gesetzt, andere Bits sind immer Null. Wir zählen also die Anzahl der gesetzten Bits mit POPCNT, und wenn es gleich 1 ist, ist die Zahl die Potenz von 2. Ich glaube, es gibt keine möglichen schnelleren Methoden. Und es ist sehr einfach, wenn Sie es einmal verstanden haben:
quelle
i && !(i & (i - 1)))
auf meinem Computer etwa 10% schneller, selbst wenn ich sicher war, den POPCNT-Befehl für native Assemblys in gcc zu aktivieren.Das Folgen wäre aufgrund des booleschen Kurzschlusses und der Tatsache, dass der Vergleich langsam ist, schneller als die am häufigsten abgestimmte Antwort.
Wenn Sie wissen, dass x nicht 0 sein kann, dann
quelle
quelle
Wenn Sie einen modernen Intel-Prozessor mit den Bit-Manipulationsanweisungen haben , können Sie Folgendes ausführen. Der reine C / C ++ - Code wird weggelassen, da andere ihn bereits beantwortet haben. Sie benötigen ihn jedoch, wenn der BMI nicht verfügbar oder aktiviert ist.
GCC, ICC und Clang signalisieren BMI-Unterstützung mit
__BMI__
. Es ist in Microsoft Compilern in Visual Studio 2015 und höher verfügbar, wenn AVX2 verfügbar und aktiviert ist . Informationen zu den benötigten Headern finden Sie unter Header-Dateien für SIMD-Eigenheiten .Normalerweise bewache ich das
_blsr_u64
mit einem_LP64_
Fall, der auf i686 kompiliert wird. Clang benötigt eine kleine Problemumgehung, da ein etwas anderer intrinsischer Symbolname verwendet wird:Diese Website wird oft zitiert: Bit Twiddling Hacks .
quelle
Dies ist nicht der schnellste oder kürzeste Weg, aber ich denke, er ist sehr gut lesbar. Also würde ich so etwas machen:
Dies funktioniert, da Binär auf Zweierpotenzen basiert. Jede Zahl mit nur einem gesetzten Bit muss eine Zweierpotenz sein.
quelle
Hier ist eine andere Methode, in diesem Fall
|
anstelle von&
:quelle
Es ist möglich durch c ++
quelle
log2
, und der Beweis, dass es funktioniert, ist nicht so einfach zu erklären (genau, können Sie von Rundungsfehlern erwischt werden?). Es ist auch unnötig verworren mitif..return..else..return
. Was ist falsch daran, es zu kollabierenreturn x==(double)y;
? Es solltebool
sowieso zurückgeben. IMO sogar ternäre Operator wäre klarer, wenn man wirklich bleiben willint
.Ich weiß, dass dies ein sehr alter Beitrag ist, aber ich dachte, es könnte interessant sein, dies hier zu posten.
Von Code-Golf SE (also alle Ehre gebührt denjenigen, die dies geschrieben haben): Showcase of Languages
(Absatz über C , Unterabsatz Länge 36 Ausschnitt )
quelle
Ein anderer Weg (vielleicht nicht der schnellste) besteht darin, festzustellen, ob ln (x) / ln (2) eine ganze Zahl ist.
quelle
Dies ist die Bitverschiebungsmethode in T-SQL (SQL Server):
Es ist viel schneller als viermal einen Logarithmus zu erstellen (erster Satz, um ein Dezimalergebnis zu erhalten, zweiter Satz, um eine Ganzzahl zu erhalten und zu vergleichen)
quelle