it-swarm.com.de

So überprüfen Sie, ob eine Zahl eine Potenz von 2 ist

Heute brauchte ich einen einfachen Algorithmus, um zu überprüfen, ob eine Zahl eine Potenz von 2 ist.

Der Algorithmus muss sein:

  1. Einfach
  2. Korrigieren Sie für jeden ulong Wert.

Ich habe mir diesen einfachen Algorithmus ausgedacht:

private bool IsPowerOfTwo(ulong number)
{
    if (number == 0)
        return false;

    for (ulong power = 1; power > 0; power = power << 1)
    {
        // This for loop used shifting for powers of 2, meaning
        // that the value will become 0 after the last shift
        // (from binary 1000...0000 to 0000...0000) then, the 'for'
        // loop will break out.

        if (power == number)
            return true;
        if (power > number)
            return false;
    }
    return false;
}

Aber dann dachte ich, wie wäre es zu überprüfen, ob log2 x ist eine genau runde Zahl? Aber als ich nach 2 ^ 63 + 1 gesucht habe, Math.Log hat wegen der Rundung genau 63 zurückgegeben. Also habe ich geprüft, ob 2 hoch 63 gleich der ursprünglichen Zahl ist - und zwar, weil die Berechnung in doubles und nicht in exakten Zahlen erfolgt:

private bool IsPowerOfTwo_2(ulong number)
{
    double log = Math.Log(number, 2);
    double pow = Math.Pow(2, Math.Round(log));
    return pow == number;
}

Dies gab true für den angegebenen falschen Wert zurück: 9223372036854775809.

Gibt es einen besseren Algorithmus?

541
configurator

Es gibt einen einfachen Trick für dieses Problem:

bool IsPowerOfTwo(ulong x)
{
    return (x & (x - 1)) == 0;
}

Beachten Sie, dass diese Funktion true für 0 Ausgibt, was keine Potenz von 2 Ist. Wenn Sie dies ausschließen möchten, gehen Sie wie folgt vor:

bool IsPowerOfTwo(ulong x)
{
    return (x != 0) && ((x & (x - 1)) == 0);
}

Erläuterung

In erster Linie der bitweise Binär- und Operator aus der MSDN-Definition:

Binär & Operatoren sind für die Integraltypen und Bool vordefiniert. Berechnet & für ganzzahlige Typen das logische bitweise UND seiner Operanden. Berechnet für bool-Operanden & das logische UND seiner Operanden; Das heißt, das Ergebnis ist genau dann wahr, wenn beide Operanden wahr sind.

Nun schauen wir uns an, wie das alles abläuft:

Die Funktion gibt einen booleschen Wert (true/false) zurück und akzeptiert einen eingehenden Parameter vom Typ unsigned long (in diesem Fall x). Nehmen wir der Einfachheit halber an, dass jemand den Wert 4 übergeben und die Funktion folgendermaßen aufgerufen hat:

bool b = IsPowerOfTwo(4)

Jetzt ersetzen wir jedes Vorkommen von x durch 4:

return (4 != 0) && ((4 & (4-1)) == 0);

Nun, wir wissen bereits, dass 4! = 0 wahr ist, soweit so gut. Aber was ist mit:

((4 & (4-1)) == 0)

Das bedeutet natürlich:

((4 & 3) == 0)

Aber was genau ist 4&3?

Die Binärdarstellung von 4 ist 100 und die Binärdarstellung von 3 ist 011 (denken Sie daran, dass & die Binärdarstellung dieser Zahlen annimmt). Also haben wir:

100 = 4
011 = 3

Stellen Sie sich vor, diese Werte werden ähnlich wie bei der elementaren Addition gestapelt. Der Operator & Sagt, dass, wenn beide Werte gleich 1 sind, das Ergebnis 1 ist, andernfalls 0. Also 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, und 0 & 1 = 0. Also rechnen wir:

100
011
----
000

Das Ergebnis ist einfach 0. Also gehen wir zurück und schauen uns an, was unsere return-Anweisung jetzt übersetzt:

return (4 != 0) && ((4 & 3) == 0);

Das heißt jetzt:

return true && (0 == 0);
return true && true;

Wir alle wissen, dass true && true Einfach true ist, und dies zeigt, dass für unser Beispiel 4 eine Potenz von 2 ist.

1143
Greg Hewgill

Einige Sites, die dieses und andere kleine Drehereien dokumentieren und erklären, sind:

Und der Opa von ihnen das Buch "Hacker's Delight" von Henry Warren, Jr. :

Wie Sean Andersons Seite erklärt, ist der Ausdruck ((x & (x - 1)) == 0) gibt fälschlicherweise an, dass 0 eine Potenz von 2 ist. Er schlägt vor, Folgendes zu verwenden:

(!(x & (x - 1)) && x)

um dieses Problem zu beheben.

95
Michael Burr

return (i & -i) == i

39
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}
22
Matt Howells

Ich habe kürzlich unter http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-two-in-c/) einen Artikel darüber geschrieben. . Es behandelt die Bitzählung, die korrekte Verwendung von Logarithmen, die klassische Prüfung "x &&! (X & (x - 1))" und andere.

20
Rick Regan

Hier ist eine einfache C++ Lösung:

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}
16
deft_code
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

Und hier ist ein allgemeiner Algorithmus, um herauszufinden, ob eine Zahl eine Potenz einer anderen Zahl ist.

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }
10
Raz Megrelidze

Der folgende Anhang zur akzeptierten Antwort kann für einige Personen nützlich sein:

Eine Zweierpotenz in Binärform sieht immer aus wie 1, gefolgt von n Nullen , wobei n größer oder gleich 0 ist. Beispiel:

Decimal  Binary
1        1     (1 followed by 0 zero)
2        10    (1 followed by 1 zero)
4        100   (1 followed by 2 zeroes)
8        1000  (1 followed by 3 zeroes)
.        .
.        .
.        .

und so weiter.

Wenn wir 1 Von dieser Art von Zahlen abziehen, werden sie zu 0, gefolgt von n Einsen und wieder ist n dasselbe wie oben. Ex:

Decimal    Binary
1 - 1 = 0  0    (0 followed by 0 one)
2 - 1 = 1  01   (0 followed by 1 one)
4 - 1 = 3  011  (0 followed by 2 ones)
8 - 1 = 7  0111 (0 followed by 3 ones)
.          .
.          .
.          .

und so weiter.

Auf den Punkt kommen

Was passiert, wenn wir ein bitweises UND einer Zahl x, die eine Potenz von 2 ist, und x - 1 Machen?

Das von x wird mit der Null von x - 1 Ausgerichtet, und alle Nullen von x werden mit Einsen von x - 1, was bewirkt, dass das bitweise UND zu 0 führt. Und so haben wir die oben erwähnte einzeilige Antwort richtig.


Weiteres Hinzufügen zur Schönheit der akzeptierten Antwort oben -

Wir haben also jetzt eine Immobilie zur Verfügung:

Wenn wir 1 von einer beliebigen Zahl subtrahieren, wird in der binären Darstellung die am weitesten rechts stehende 1 zu 0 und alle Nullen vor dieser am weitesten rechts liegenden 1 werden jetzt zu 1

Eine großartige Verwendung dieser Eigenschaft ist das Herausfinden von - Wie viele Einsen sind in der Binärdarstellung einer bestimmten Zahl vorhanden? Der kurze und süße Code, um dies für eine bestimmte Ganzzahl zu tun x ist:

byte count = 0;
for ( ; x != 0; x &= (x - 1)) count++;
Console.Write("Total ones in the binary representation of x = {0}", count);

Ein weiterer Aspekt von Zahlen, der anhand des oben erläuterten Konzepts bewiesen werden kann, ist "Kann jede positive Zahl als die Summe der Potenzen von 2 dargestellt werden?".

Ja, jede positive Zahl kann als Summe der Potenzen von 2 dargestellt werden. Nehmen Sie für jede Zahl die binäre Darstellung. Bsp .: Nehmen Sie die Nummer 117.

The binary representation of 117 is 1110101

Because  1110101 = 1000000 + 100000 + 10000 + 0000 + 100 + 00 + 1
we have  117     = 64      + 32     + 16    + 0    + 4   + 0  + 1
10
displayName

Nachdem ich die Frage gestellt hatte, dachte ich an die folgende Lösung:

Wir müssen überprüfen, ob genau eine der Binärziffern eine ist. Also verschieben wir einfach die Zahl um eine Stelle nach rechts und geben true zurück, wenn sie gleich 1 ist. Wenn wir zu irgendeinem Zeitpunkt eine ungerade Zahl haben ((number & 1) == 1), wir wissen, dass das Ergebnis false ist. Dies erwies sich (unter Verwendung eines Benchmarks) als etwas schneller als die ursprüngliche Methode für (große) wahre Werte und viel schneller für falsche oder kleine Werte.

private static bool IsPowerOfTwo(ulong number)
{
    while (number != 0)
    {
        if (number == 1)
            return true;

        if ((number & 1) == 1)
            // number is an odd number and not 1 - so it's not a power of two.
            return false;

        number = number >> 1;
    }
    return false;
}

Natürlich ist Gregs Lösung viel besser.

10
configurator
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
6
abelenky
return ((x != 0) && !(x & (x - 1)));

Wenn x eine Zweierpotenz ist, befindet sich sein einzelnes 1-Bit an der Position n. Dies bedeutet, dass x – 1 An Position n eine 0 hat. Um zu sehen, warum, erinnern Sie sich, wie eine binäre Subtraktion funktioniert. Wenn Sie 1 von x subtrahieren, wird der Kredit bis zur Position n weitergegeben. Bit n wird 0 und alle niedrigeren Bits werden 1. Da x keine 1-Bits gemeinsam mit x – 1 hat, ist x & (x – 1) 0 und !(x & (x – 1)) ist wahr.

4
Prakash Jat
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

Das geht wirklich schnell. Es dauert ungefähr 6 Minuten und 43 Sekunden, um alle 2 ^ 32 Ganzzahlen zu überprüfen.

4
sudeepdino008
bool isPowerOfTwo(int x_)
{
  register int bitpos, bitpos2;
  asm ("bsrl %1,%0": "+r" (bitpos):"rm" (x_));
  asm ("bsfl %1,%0": "+r" (bitpos2):"rm" (x_));
  return bitpos > 0 && bitpos == bitpos2;
}
4
bugs king

Finden Sie heraus, ob die angegebene Zahl eine Potenz von 2 ist.

#include <math.h>

int main(void)
{
    int n,logval,powval;
    printf("Enter a number to find whether it is s power of 2\n");
    scanf("%d",&n);
    logval=log(n)/log(2);
    powval=pow(2,logval);

    if(powval==n)
        printf("The number is a power of 2");
    else
        printf("The number is not a power of 2");

    getch();
    return 0;
}
4
udhaya

Hier ist eine andere Methode, die ich mir ausgedacht habe, in diesem Fall mit | anstatt &:

bool is_power_of_2(ulong x) {
    if(x ==  (1 << (sizeof(ulong)*8 -1) ) return true;
    return (x > 0) && (x<<1 == (x|(x-1)) +1));
}
3
Chethan

Eine Zahl ist eine Potenz von 2, wenn sie nur 1 gesetztes Bit enthält. Wir können diese Eigenschaft und die generische Funktion countSetBits verwenden, um herauszufinden, ob eine Zahl die Potenz 2 hat oder nicht.

Dies ist ein C++ - Programm:

int countSetBits(int n)
{
        int c = 0;
        while(n)
        {
                c += 1;
                n  = n & (n-1);
        }
        return c;
}

bool isPowerOfTwo(int n)
{        
        return (countSetBits(n)==1);
}
int main()
{
    int i, val[] = {0,1,2,3,4,5,15,16,22,32,38,64,70};
    for(i=0; i<sizeof(val)/sizeof(val[0]); i++)
        printf("Num:%d\tSet Bits:%d\t is power of two: %d\n",val[i], countSetBits(val[i]), isPowerOfTwo(val[i]));
    return 0;
}

Wir müssen nicht explizit prüfen, ob 0 eine Potenz von 2 ist, da auch für 0 False zurückgegeben wird.

AUSGABE

Num:0   Set Bits:0   is power of two: 0
Num:1   Set Bits:1   is power of two: 1
Num:2   Set Bits:1   is power of two: 1
Num:3   Set Bits:2   is power of two: 0
Num:4   Set Bits:1   is power of two: 1
Num:5   Set Bits:2   is power of two: 0
Num:15  Set Bits:4   is power of two: 0
Num:16  Set Bits:1   is power of two: 1
Num:22  Set Bits:3   is power of two: 0
Num:32  Set Bits:1   is power of two: 1
Num:38  Set Bits:3   is power of two: 0
Num:64  Set Bits:1   is power of two: 1
Num:70  Set Bits:3   is power of two: 0
3
jerrymouse

für jede Potenz von 2 gilt auch Folgendes.

n & (- n) == n

HINWEIS: Schlägt bei n = 0 fehl, muss also überprüft werden
Der Grund, warum dies funktioniert, ist:
- n ist das 2s-Komplement von n. -n hat jedes Bit links von dem ganz rechts gesetzten Bit von n im Vergleich zu n umgedreht. Für Zweierpotenzen gibt es nur ein gesetztes Bit.

2
FReeze FRancis

Verbesserung der Antwort von @ user134548 ohne Bit-Arithmetik:

public static bool IsPowerOfTwo(ulong n)
{
    if (n % 2 != 0) return false;  // is odd (can't be power of 2)

    double exp = Math.Log(n, 2);
    if (exp != Math.Floor(exp)) return false;  // if exp is not integer, n can't be power
    return Math.Pow(2, exp) == n;
}

Das funktioniert gut für:

IsPowerOfTwo(9223372036854775809)
2
rhodan

Beispiel

0000 0001    Yes
0001 0001    No

Algorithmus

  1. Teilen Sie mit einer Bitmaske NUM die Variable in binär

  2. IF R > 0 AND L > 0: Return FALSE

  3. Andernfalls wird NUM zu dem Wert ungleich Null

  4. IF NUM = 1: Return TRUE

  5. Fahren Sie andernfalls mit Schritt 1 fort

Komplexität

Zeit ~ O(log(d)) wobei d die Anzahl der Binärziffern ist

2
Khaled.K

Dieses Programm in Java gibt "true" zurück, wenn number eine Potenz von 2 ist, und "false", wenn es keine Potenz von 2 ist

// To check if the given number is power of 2

import Java.util.Scanner;

public class PowerOfTwo {
    int n;
    void solve() {
        while(true) {
//          To eleminate the odd numbers
            if((n%2)!= 0){
                System.out.println("false");
                break;
            }
//  Tracing the number back till 2
            n = n/2;
//  2/2 gives one so condition should be 1
            if(n == 1) {
                System.out.println("true");
                break;
            }
        }
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        PowerOfTwo obj = new PowerOfTwo();
        obj.n = in.nextInt();
        obj.solve();
    }

}

OUTPUT : 
34
false

16
true
1
Kaushik Holla
private static bool IsPowerOfTwo(ulong x)
{
    var l = Math.Log(x, 2);
    return (l == Math.Floor(l));
}
0
user134548

gebe i> 0 && (i ^ -i (-i << 1);) == zurück

Ich habe eine solche Antwort nicht gefunden. Lass es meins sein

0
Aliaksei Yatsau