Bir sayının 2'nin gücü olup olmadığı nasıl kontrol edilir


584

Bugün bir sayının 2'nin gücü olup olmadığını kontrol etmek için basit bir algoritmaya ihtiyacım vardı.

Algoritmanın olması gerekir:

  1. Basit
  2. Herhangi bir ulongdeğer için düzeltin .

Bu basit algoritmayı buldum:

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;
}

Ama sonra düşündüm, tam olarak yuvarlak bir sayı olup olmadığını kontrol etmeye ne dersiniz ? Ama 2 ^ 63 + 1 için kontrol ettiğimde , yuvarlama nedeniyle tam olarak 63 döndü. Bu nedenle, güç 63'ün 2'sinin orijinal sayıya eşit olup olmadığını kontrol ettim - ve çünkü hesaplama tam sayılarda değil s cinsinden yapılır :log2 xMath.Logdouble

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

Bu iade trueverilen yanlış değeri için: 9223372036854775809.

Daha iyi bir algoritma var mı?


1
Bence çözüm ikisinin gücünün bir toplamı (x & (x - 1))olduğunda yanlış pozitifler verebilir X, örn 8 + 16.
Joe Brown

32
Tüm sayılar ikinin güçlerinin toplamı olarak yazılabilir, bu yüzden ikili sayıdaki herhangi bir sayıyı temsil edebiliriz. Dahası, örneğiniz yanlış bir pozitif döndürmez, çünkü 11000 & 10111 = 10000! = 0.
vlsd

1
@JoeBrown Yanlış pozitifleri yok. Aslında ifade, iki gücün toplamından daha büyük olanını döndürür.
Samy Bencherif

Yanıtlar:


1219

Bu sorun için basit bir hile var:

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

Not, bu işlev trueiçin 0bir güç değil, rapor verecektir 2. Bunu hariç tutmak istiyorsanız, şu şekilde:

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

açıklama

Her şeyden önce, bit tanımı ikili ve operatör MSDN tanımından:

İkili ve operatörler, integral tipleri ve bool için önceden tanımlanmıştır. İntegral türler için & mantıksal bitsel VE işlenenlerinin mantıksal hesaplar. Bool işlenenleri için & işlenenlerinin mantıksal AND'ini hesaplar; yani, sonuç yalnızca ve her iki işleneninin de doğru olması durumunda doğrudur.

Şimdi bunların nasıl oynandığına bir göz atalım:

İşlev boolean (true / false) döndürür ve unsigned long türünde bir gelen parametre kabul eder (bu durumda x). Basitlik uğruna, birisinin 4 değerini geçtiğini ve işlevi şöyle çağırdığını varsayalım:

bool b = IsPowerOfTwo(4)

Şimdi x'in her oluşumunu 4 ile değiştiriyoruz:

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

Biz zaten biliyoruz ki 4! = 0 gerçek doğrular, şimdiye kadar iyi. Ama ne hakkında:

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

Bu elbette bununla ilgilidir:

((4 & 3) == 0)

Ama tam olarak nedir 4&3?

4'ün ikili gösterimi 100'dür ve 3'ün ikili gösterimi 011'dir (bu sayıların ikili gösterimini & alır). Böylece sahibiz:

100 = 4
011 = 3

Bu değerlerin, temel toplama gibi yığıldığını düşünün. &Operatör aksi takdirde 0. Yani olduğunu her iki değer 1'e eşit olup olmadığını o zaman sonuç 1 olduğunu söylüyor 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0ve 0 & 1 = 0. Bu yüzden matematiği yapıyoruz:

100
011
----
000

Sonuç sadece 0'dır. Bu yüzden geri dönüp iade beyanımızın ne anlama geldiğine bakıyoruz:

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

Şimdi şu anlama gelir:

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

Hepimiz true && truebunun basit olduğunu biliyoruz trueve bu, örneğimiz için 4'ün 2'nin gücü olduğunu gösterir.


56
@Kripp: Sayı 1000 ... 000 ikili biçiminde olacaktır. -1 yaptığınızda, 0111 ... 111 biçiminde olacaktır. Böylece, iki sayının ikili ve sonuç 000000 olur. Bu ikişer ikişer olmayanlar için olmazdı, çünkü 1010100 örneğin 1010011 olur ve sonuç olarak (devam ...)
yapılandırıcı

47
... ikili ve sonra bir 1010000 sonuçlandı. Tek yanlış pozitif 0 olurdu, bu yüzden kullanacağım: return (x! = 0) && ((x & (x - 1)) == 0);
yapılandırıcı

6
Kripp, düşünün (2: 1, 10: 1) (4: 3, 100: 11) (8: 7, 1000: 111) (16:15, 10000: 1111) Desene bakın?
Thomas L Holaday

13
@ShuggyCoUk: ikisinin tamamlayıcısı negatif sayıların nasıl temsil edildiği. Bu işaretsiz bir tam sayı olduğu için negatif sayıların gösterimi uygun değildir. Bu teknik yalnızca negatif olmayan tam sayıların ikili temsilini temel alır.
Greg Hewgill

4
@SoapBox - daha yaygın olan nedir? İkisinin gücü olmayan sıfırlar veya sıfır olmayan sayılar? Bu, daha fazla bağlam olmadan cevaplayamayacağınız bir soru. Ve gerçekten, gerçekten önemli değil.
yapılandırıcı

97

Bunu belgeleyen ve açıklayan bazı siteler ve diğer bit salaklar:

Ve onların büyükbabası Henry Warren, Jr.'ın "Hacker's Delight" adlı kitabı :

As Sean Anderson'ın sayfa açıklar ifadesi ((x & (x - 1)) == 0)yanlış 0 O kullanımına işaret 2'in üssü olduğunu gösterir:

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

bu sorunu düzeltmek için.


4
0, 2 ... 2 ^ -inf = 0.;););)
Michael Bray

4
Bu bir C # etiketli iş parçacığı olduğundan !, yalnızca Boole türlerine uygulanabildiğinden ve &&her iki işlenenin de boole olmasını gerektirdiğinden (Sean Anderson'ın son ifadesinin) C # 'da yasadışı olduğunu belirtmek gerekir. (Kullanıcı tanımlı işleçler hariç) başka şeyler mümkün kılmak, ancak bunun için uygun değildir ulong).
Jeppe Stig Nielsen

40

return (i & -i) == i


2
bunun neden işe yarayıp yaramayacağına dair bir ipucu var mı? i sadece imzalı ints / uzun olduğu sadece java, doğruluğunu kontrol etti. eğer doğruysa, bu en üstün cevap olacaktır. daha hızlı + daha küçük
Andreas Petersson

7
İkinin tamamlayıcı gösteriminin özelliklerinden birini kullanır: bir sayının negatif değerini hesaplamak için bitsel bir olumsuzlama gerçekleştirir ve sonuca 1 eklersiniz. En az anlamlı biti iayarlanmış olarak da ayarlanır -i. Aşağıdaki bitler 0 olacaktır (her iki değerde), yukarıdaki bitler birbirine göre ters çevrilecektir. Bu i & -inedenle değeri, en az anlamlı set biti olacaktır i(ki bu iki değerin gücüdür). Eğer idaha sonra aynı değere sahip tek ucu seti oldu. iAynı nedenden dolayı 0 olduğunda başarısız olur i & (i - 1) == 0.
Michael Carman

6
Eğer iimzasız türüdür ikiler tamamlayıcı onunla ilgisi yok. Sadece modüler aritmetik ve bitsel özelliklerinden faydalanırsınız.
R .. GitHub BUZA YARDIMCI DURDUR

2
Bu takdirde çalışmaz i==0(döner (0&0==0)ki true). O olmalıreturn i && ( (i&-i)==i )
bobobobo

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

3
Bu çözüm daha iyidir çünkü negatif geçebiliyorsa negatif sayı ile de başa çıkabilir. (Ulong yerine uzunsa)
Steven

Neden ondalık bu durumda ikinin gücü olarak geçer?
chris Frisina


17

İşte basit bir C ++ çözümü:

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}

8
gcc'de bu, denilen tek bir gcc yerleşikine derlenir __builtin_popcount. Ne yazık ki, bir işlemci ailesi henüz bunu yapmak için tek bir montaj talimatına sahip değil (x86), bu nedenle bit sayımı için en hızlı yöntem. Diğer herhangi bir mimaride bu tek bir montaj talimatıdır.
deft_code

3
@deft_code daha yeni x86 mikro mimarileri desteğipopcnt
phuclv

13

Kabul edilen cevaba aşağıdaki ek, bazı insanlar için yararlı olabilir:

İkili güç, ikili olarak ifade edildiğinde, her zaman 1 gibi görünür, ardından n sıfır gelir, burada n, sıfırdan büyük veya ona eşittir. Örn:

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)
.        .
.        .
.        .

ve bunun gibi.

Biz çıkardığınızda 1sayıların bu tür, onlar haline n olanlar tarafından takip 0 ve yine n yukarıda aynıdır. Ör:

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)
.          .
.          .
.          .

ve bunun gibi.

En önemli nokta

Bit şeklinde VE bir sayı xolan 2'nin gücü olan ve ne yaptığımızda ne olur x - 1?

Birinin xsıfırı ile hizalanır x - 1ve sıfırların tümü xile hizalanır x - 1, bu da bitsel AND'in 0 ile sonuçlanmasına neden olur. Ve yukarıda belirtilen tek satır cevabının doğru olması bu şekilde olur.


Yukarıda kabul edilen cevabın güzelliğine ek olarak -

Şimdi elimizde bir mülk var:

Herhangi bir sayıdan 1 çıkardığımızda, ikili gösterimde en sağdaki 1 0 olur ve en sağdaki 1'den önceki tüm sıfırlar şimdi 1 olur

Bu özelliğin harika bir kullanımı bulmak - Belirli bir sayının ikili gösteriminde kaç tane 1 var? Belirli bir tamsayı için bunu yapmanın kısa ve tatlı kodu x:

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

Sayıların yukarıda açıklanan kavramdan kanıtlanabilecek bir diğer yönü de "Her pozitif sayı 2'nin gücü toplamı olarak temsil edilebilir mi?" .

Evet, her pozitif sayı 2'nin güçlerinin toplamı olarak temsil edilebilir. Herhangi bir sayı için ikili temsilini alın. Örn: Numara al 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

@Michi: Bir yerde 0'ın pozitif bir sayı olduğunu iddia ettim mi? Yoksa 2 kişilik bir güç mü?
displayName

Evet, 0'ı örnek olarak koyarak ve bu matematiği ikili gösterimin içine koyarak . Bir Karışıklık yaratır.
Michi

1
İki sayı eklemek, pozitif olmaları gerektiğine inanmanızı karıştırırsa, bu konuda hiçbir şey yapamam. Ayrıca, temsilde 0'ların, bu gücün 2 gücünün atlandığını ima ettiği gösterilmiştir. Temel matematiği bilen herkes, 0 eklemenin hiçbir şey eklememek anlamına geldiğinin farkındadır.
displayName

10

Soruyu gönderdikten sonra aşağıdaki çözümü düşündüm:

İkili rakamlardan birinin tam olup olmadığını kontrol etmeliyiz. Bu yüzden sayıyı bir seferde bir basamak sağa kaydırırız ve true1'e eşitse geri döneriz. Herhangi bir noktada tek bir sayı gelirsek ( (number & 1) == 1), sonucun olduğunu biliyoruz false. Bu, (bir kıyaslama kullanarak) (büyük) gerçek değerler için orijinal yöntemden biraz daha hızlı ve yanlış veya küçük değerler için çok daha hızlı olduğunu kanıtladı.

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;
}

Elbette Greg'in çözümü çok daha iyi.


10
    bool IsPowerOfTwo(int n)
    {
        if (n > 1)
        {
            while (n%2 == 0)
            {
                n >>= 1;
            }
        }
        return n == 1;
    }

Ve işte bir sayının başka bir sayının gücü olup olmadığını öğrenmek için genel bir algoritma.

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

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

1
Bu c#mu? Ben bu olduğunu tahmin c++olarak xbir bool olarak döndürülür.
Mariano Desanze

1
C ++ olarak yazdım. C # yapmak önemsiz: bool isPow2 = ((x & ~ (x-1)) == x)? x! = 0: yanlış;
abelenky

4

Verilen sayının 2 gücü olup olmadığını bulun.

#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;
}

Veya, C #: return x == Math.Pow (2, Math.Log (x, 2));
yapılandırıcı

4
Kırık. Büyük kayan nokta yuvarlama sorunlarından muzdarip. Kayan nokta kullanmak istiyorsanız frexpkötü logşeyler yerine kullanın .
R .. GitHub DURDURMA BUZA YARDIM

4
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
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

Bu gerçekten hızlı. Tüm 2 ^ 32 tam sayılarının kontrol edilmesi yaklaşık 6 dakika 43 saniye sürer.


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

Eğer xikisinin bir güçtür, onun yalnız 1 bit pozisyonunda n. Bu x – 1, 0 konumunda demektir n. Nedenini görmek için ikili çıkarma işleminin nasıl çalıştığını hatırlayın. 1 çıkarılırken x, borçlanma pozisyonuna kadar yayılır n; bit n0 olur ve tüm alt bitler 1 olur. Şimdi, x1 bit ile ortak olmadığı için x – 1, x & (x – 1)0 ve !(x & (x – 1))doğrudur.


3

Bir sayı, yalnızca 1 set biti içeriyorsa 2'nin gücüdür. countSetBitsBir sayının 2 gücü olup olmadığını bulmak için bu özelliği ve genel işlevi kullanabiliriz.

Bu bir C ++ programıdır:

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;
}

0'ın 2 için bir Güç olup olmadığını açıkça kontrol etmemiz gerekmez, çünkü 0 için False değerini de döndürür.

ÇIKTI

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

işlev 'ulong' dönüş türüne sahip olduğunda c'yi 'int' olarak döndürmek? Bir kullanma whileyerine ait if? Şahsen bir neden göremiyorum ama işe yarıyor gibi görünüyor. DÜZENLEME: - hayır ... bu daha birşey daha üstü için 1 dönecektir 0!?
James Khoury

@JamesKhoury Bir c ++ programı yazıyordum, bu yüzden yanlış bir şekilde int döndüm. Ancak bu küçük bir yazım hatasıydı ve bir düşüşü hak etmedi. Ancak yorumunuzun geri kalanının nedenini "if yerine" kullanarak "ve" 0'dan büyük herhangi bir şey için 1 döndürür "ifadesini anlayamıyorum. Çıkışı kontrol etmek için ana saplamayı ekledim. AFAIK beklenen çıktıdır. Yanlışım varsa düzelt.
jerrymouse

3

İşte bu durumda |yerine kullanarak, başka bir yöntem geliştirdi &:

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));
}

(x > 0)Burada biraz ihtiyacın var mı?
yapılandırıcı

@configurator, evet, aksi halde is_power_of_2 (0) true
değerini

3

2'nin herhangi bir gücü için aşağıdakiler de geçerlidir.

n (- N) == N

NOT: n = 0 için başarısız, bu yüzden kontrol etmeniz gerekir
Neden bu çalışır:
-n n 2s tamamlayıcısıdır. -n, n ile karşılaştırıldığında, her bir bitin sağındaki n ayarlanmış bitin soluna sahip olacaktır. 2 gücü için sadece bir set biti vardır.


2

Misal

0000 0001    Yes
0001 0001    No

Algoritma

  1. Bir bit maskesi kullanarak NUM, değişkeni ikili dosyaya bölün

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

  3. Aksi takdirde, NUMsıfır olmayan kişi olur

  4. IF NUM = 1: Return TRUE

  5. Aksi takdirde, Adım 1'e gidin

karmaşa

Zaman ~ ikili basamak sayısı O(log(d))nereded


1

@ User134548'in yanıtını aritmetik olmadan iyileştirme:

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;
}

Bu, aşağıdakiler için iyi çalışır:

IsPowerOfTwo(9223372036854775809)

kayan nokta işlemleri basit bir bitsel ifadeden çok daha yavaştır
phuclv

1

Mark önerdi Gravell bu .NET Çekirdek 3, varsa System.Runtime.Intrinsics.X86.Popcnt.PopCount

public bool IsPowerOfTwo(uint i)
{
    return Popcnt.PopCount(i) == 1
}

Tek komut, daha hızlı (x != 0) && ((x & (x - 1)) == 0)ama daha az taşınabilir.


Bundan daha hızlı olduğuna emin misin (x != 0) && ((x & (x - 1)) == 0)? Bundan şüpheliyim, özellikle. popcnt'nin kullanılamadığı eski sistemlerde
phuclv

Daha hızlı değil. Ben sadece modern bir Intel CPU üzerinde test ve sökme kullanımda POPCNT doğruladı (verilen, C kodu, .NET değil). POPCNT genel olarak bitleri saymak için daha hızlıdır, ancak tek bitlik durum için bit döndürme hilesi hala% 10 daha hızlıdır.
eraoul

Hata! Geri alıyorum. Şube tahmininin "hile" olduğunu düşündüğüm bir döngüde test yapıyordum. POPCNT gerçekten de tek bir saat döngüsünde çalışan ve mevcutsa daha hızlı olan tek bir talimattır.
eraoul

0

C'de, i && !(i & (i - 1)hile test ettim __builtin_popcount(i)ve CPU'da gcc kullanarak, CPU'nun POPCNT talimatını kullandığınızdan emin olmak için -mpopcnt bayrağıyla karşılaştırdım. Test programım 0 ile 2 ^ 31 arasında tam sayı olan iki sayıyı saydı.

İlk başta i && !(i & (i - 1)POPCNT'nin kullandığım demontajda kullanıldığını doğrulasam da,% 10 daha hızlı olduğunu düşündüm __builtin_popcount.

Bununla birlikte, bir if ifadesi eklediğimi fark ettim ve şube tahmini muhtemelen biraz dönen versiyonda daha iyi gidiyordu. İf'yi kaldırdım ve POPCNT beklendiği gibi daha hızlı sona erdi.

Sonuçlar:

Intel (R) Core (TM) i7-4771 CPU maksimum 3.90GHz

Timing (i & !(i & (i - 1))) trick
30

real    0m13.804s
user    0m13.799s
sys     0m0.000s

Timing POPCNT
30

real    0m11.916s
user    0m11.916s
sys     0m0.000s

AMD Ryzen Threadripper 2950X 16 Çekirdekli İşlemci max 3.50GHz

Timing (i && !(i & (i - 1))) trick
30

real    0m13.675s
user    0m13.673s
sys 0m0.000s

Timing POPCNT
30

real    0m13.156s
user    0m13.153s
sys 0m0.000s

Burada Intel CPU'nun biraz twiddling ile AMD'den biraz daha yavaş göründüğünü, ancak çok daha hızlı bir POPCNT'ye sahip olduğunu unutmayın; AMD POPCNT fazla bir destek sağlamaz.

popcnt_test.c:

#include "stdio.h"

// Count # of integers that are powers of 2 up to 2^31;
int main() {
  int n;
  for (int z = 0; z < 20; z++){
      n = 0;
      for (unsigned long i = 0; i < 1<<30; i++) {
       #ifdef USE_POPCNT
        n += (__builtin_popcount(i)==1); // Was: if (__builtin_popcount(i) == 1) n++;
       #else
        n += (i && !(i & (i - 1)));  // Was: if (i && !(i & (i - 1))) n++;
       #endif
      }
  }

  printf("%d\n", n);
  return 0;
}

Testleri çalıştırın:

gcc popcnt_test.c -O3 -o test.exe
gcc popcnt_test.c -O3 -DUSE_POPCNT -mpopcnt -o test-popcnt.exe

echo "Timing (i && !(i & (i - 1))) trick"
time ./test.exe

echo
echo "Timing POPCNT"
time ./test-opt.exe

0

Görüyorum ki birçok cevap n &&! (N & (n - 1)) döndürmeyi öneriyor ama benim girişime göre negatif değerler yanlış değerler veriyor. Burada bir başka basit yaklaşım paylaşacağım, çünkü iki sayının gücünün sadece bir set biti olduğunu biliyoruz, bu yüzden O (log N) zamanını alacak set bit sayısını sayarız.

while (n > 0) {
    int count = 0;
    n = n & (n - 1);
    count++;
}
return count == 1;

Hayır saymak için bu makaleye göz atın . set bitlerinin


-1
private static bool IsPowerOfTwo(ulong x)
{
    var l = Math.Log(x, 2);
    return (l == Math.Floor(l));
}

Bunu 9223372036854775809 numarası için deneyin. Çalışıyor mu? Yuvarlama hataları yüzünden düşünmüyorum.
yapılandırıcı

1
@configurator 922337203685477580_9_ benim için 2 gücü gibi görünmüyor;)
Kirschstein

1
@Kirschstein: Bu sayı ona yanlış bir pozitif verdi.
Erich Mirabal

7
Kirschstein: Bana da benzemiyor. Yine de işleve benziyor ...
yapılandırıcı

-2

Java 2'deki bir güçse, bu program "true" değerini ve 2'nin bir gücü değilse "false" değerini döndürür.

// 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
Bu soru C # olarak etiketlenir ve çözüm önceki çözümlere göre de çok yavaş [
phuclv
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.