Cara memeriksa apakah angka adalah kekuatan 2

585

Hari ini saya membutuhkan algoritma sederhana untuk memeriksa apakah angka adalah kekuatan 2.

Algoritma tersebut harus:

  1. Sederhana
  2. Benar untuk ulongnilai apa pun .

Saya datang dengan algoritma sederhana ini:

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

Tapi kemudian saya berpikir, bagaimana kalau mengecek apakah angka bulat persis? Tetapi ketika saya memeriksa 2 ^ 63 +1, dikembalikan persis 63 karena pembulatan. Jadi saya memeriksa apakah 2 pangkat 63 sama dengan angka asli - dan itu, karena perhitungan dilakukan dalam s dan bukan dalam angka pastinya: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;
}

Ini kembali trueuntuk nilai yang salah yang diberikan: 9223372036854775809.

Apakah ada algoritma yang lebih baik?

konfigurator
sumber
1
Saya pikir solusinya (x & (x - 1))dapat mengembalikan positif palsu ketika Xjumlah kekuatan dua, misalnya 8 + 16.
Joe Brown
32
Semua angka dapat ditulis sebagai jumlah dari kekuatan dua, itu sebabnya kami dapat mewakili angka dalam biner. Lebih jauh, contoh Anda tidak menghasilkan false positive, karena 11000 & 10111 = 10.000! = 0.
vlsd
1
@ JoBrown Tidak memiliki kesalahan positif. Bahkan ekspresi mengembalikan jumlah yang lebih besar dari jumlah dua kekuatan dari dua.
Samy Bencherif

Jawaban:

1220

Ada trik sederhana untuk masalah ini:

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

Catatan, fungsi ini akan melaporkan trueuntuk 0, yang bukan merupakan kekuatan 2. Jika Anda ingin mengecualikan itu, berikut caranya:

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

Penjelasan

Pertama dan terutama, biner & operator bitwise dari definisi MSDN:

Biner & operator sudah ditentukan sebelumnya untuk tipe dan bool yang tidak terpisahkan. Untuk tipe integral, & hitung bitwise logis DAN operandnya. Untuk operan bool, & hitung logika AND operannya; yaitu, hasilnya benar jika dan hanya jika kedua operannya benar.

Sekarang mari kita lihat bagaimana semua ini berlangsung:

Fungsi mengembalikan boolean (true / false) dan menerima satu parameter masuk bertipe unsigned long (x, dalam kasus ini). Mari kita demi kesederhanaan menganggap bahwa seseorang telah melewati nilai 4 dan memanggil fungsi seperti ini:

bool b = IsPowerOfTwo(4)

Sekarang kami mengganti setiap kemunculan x dengan 4:

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

Ya, kita sudah tahu bahwa 4! = 0 bernilai true, sejauh ini bagus. Tapi bagaimana dengan:

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

Ini diterjemahkan menjadi ini tentu saja:

((4 & 3) == 0)

Tapi apa sebenarnya itu 4&3?

Representasi biner dari 4 adalah 100 dan representasi biner dari 3 adalah 011 (ingat & mengambil representasi biner dari angka-angka ini). Jadi kita punya:

100 = 4
011 = 3

Bayangkan nilai-nilai ini ditumpuk seperti penambahan dasar. The &Operator mengatakan bahwa jika kedua nilai-nilai yang sama dengan 1 maka hasilnya adalah 1, jika tidak 0. Jadi 1 & 1 = 1, 1 & 0 = 0, 0 & 0 = 0, dan 0 & 1 = 0. Jadi kami menghitung:

100
011
----
000

Hasilnya hanya 0. Jadi kita kembali dan melihat apa yang diterjemahkan oleh pernyataan pengembalian sekarang:

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

Yang diterjemahkan sekarang menjadi:

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

Kita semua tahu itu true && truesederhana true, dan ini menunjukkan bahwa sebagai contoh kita, 4 adalah kekuatan 2.

Greg Hewgill
sumber
56
@Kripp: Jumlahnya akan dari bentuk biner 1000 ... 000. Ketika Anda -1 itu, itu akan menjadi bentuk 0111 ... 111. Dengan demikian, biner dua angka dan hasilnya adalah 000000. Ini tidak akan terjadi untuk non-power-of-twos, karena 1010100 misalnya akan menjadi 1010011, menghasilkan (lanjutan ...)
konfigurator
47
... Menghasilkan 1010000 setelah biner dan. Satu-satunya false positive adalah 0, itulah sebabnya saya akan menggunakan: return (x! = 0) && ((x & (x - 1)) == 0);
configurator
6
Kripp, pertimbangkan (2: 1, 10: 1) (4: 3, 100: 11) (8: 7, 1000: 111) (16:15, 10000: 1111) Lihat polanya?
Thomas L Holaday
13
@ShuggyCoUk: komplemen dua adalah bagaimana angka negatif direpresentasikan. Karena ini adalah bilangan bulat yang tidak ditandatangani, representasi bilangan negatif tidak relevan. Teknik ini hanya bergantung pada representasi biner dari bilangan bulat negatif.
Greg Hewgill
4
@SoapBox - apa yang lebih umum? Angka nol atau bukan nol yang bukan kekuatan dua? Ini adalah pertanyaan yang tidak dapat Anda jawab tanpa lebih banyak konteks. Dan itu benar- benar tidak penting.
konfigurator
97

Beberapa situs yang mendokumentasikan dan menjelaskan ini dan peretasan twiddling lainnya adalah:

Dan nenek moyang mereka, buku "Hacker's Delight" oleh Henry Warren, Jr .:

Seperti yang dijelaskan oleh halaman Sean Anderson , ungkapan yang ((x & (x - 1)) == 0)salah mengindikasikan bahwa 0 adalah kekuatan 2. Ia menyarankan untuk menggunakan:

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

untuk memperbaiki masalah itu.

Michael Burr
sumber
4
0 adalah kekuatan 2 ... 2 ^ -inf = 0.;););)
Michael Bray
4
Karena ini adalah utas bertanda C # , perlu menunjukkan bahwa ekspresi terakhir (dari Sean Anderson) adalah ilegal dalam C # karena !hanya dapat diterapkan pada tipe boolean, dan &&juga mengharuskan kedua operan menjadi boolean- (Kecuali operator yang ditentukan pengguna membuat hal-hal lain menjadi mungkin, tetapi itu tidak relevan untuk ulong.)
Jeppe Stig Nielsen
40

return (i & -i) == i

Andreas Petersson
sumber
2
ada petunjuk mengapa ini bisa atau tidak akan berhasil? saya memeriksa kebenarannya di java saja, di mana hanya ada ints / long ditandatangani. jika itu benar, ini akan menjadi jawaban superior. lebih cepat + lebih kecil
Andreas Petersson
7
Ini mengambil keuntungan dari salah satu properti notasi dua komplemen: untuk menghitung nilai negatif dari angka yang Anda lakukan negasi bitwise dan menambahkan 1 ke hasilnya. Bit paling tidak signifikan iyang diatur juga akan ditetapkan -i. Bit di bawah itu akan menjadi 0 (di kedua nilai) sedangkan bit di atasnya akan terbalik sehubungan satu sama lain. Nilai i & -ikarena itu akan menjadi bit set paling tidak signifikan i(yang merupakan kekuatan dua). Jika imemiliki nilai yang sama maka itu hanya set bit. Gagal ketika i0 untuk alasan yang i & (i - 1) == 0sama.
Michael Carman
6
Jika imerupakan tipe yang tidak ditandatangani, dua pelengkap tidak ada hubungannya dengan itu. Anda hanya mengambil keuntungan dari sifat-sifat aritmatika modular dan bitwise dan.
R .. GitHub BERHENTI MEMBANTU ICE
2
Ini tidak berfungsi jika i==0(mengembalikan (0&0==0)yang ada true). Seharusnyareturn i && ( (i&-i)==i )
bobobobo
22
bool IsPowerOfTwo(ulong x)
{
    return x > 0 && (x & (x - 1)) == 0;
}
Matt Howells
sumber
3
Solusi ini lebih baik karena dapat juga menangani angka negatif jika negatif dapat lewat. (Jika panjang alih-alih ulong)
Steven
Mengapa desimal lulus sebagai kekuatan dua dalam kasus ini?
chris Frisina
17

Inilah solusi C ++ sederhana :

bool IsPowerOfTwo( unsigned int i )
{
    return std::bitset<32>(i).count() == 1;
}
deft_code
sumber
8
pada gcc ini mengkompilasi ke sebuah builtin gcc tunggal yang disebut __builtin_popcount. Sayangnya, satu keluarga prosesor belum memiliki instruksi perakitan tunggal untuk melakukan ini (x86), jadi itu adalah metode tercepat untuk penghitungan bit. Pada arsitektur lain ini adalah instruksi perakitan tunggal.
deft_code
3
@deft_code dukungan popcnt
xarch
13

Adendum berikut untuk jawaban yang diterima mungkin bermanfaat bagi sebagian orang:

Kekuatan dua, ketika diekspresikan dalam biner, akan selalu terlihat seperti 1 diikuti oleh n nol di mana n lebih besar dari atau sama dengan 0. Ex:

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

dan seterusnya.

Ketika kita kurangi 1dari angka-angka ini, angka itu menjadi 0 diikuti oleh n dan lagi sama seperti di atas. 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)
.          .
.          .
.          .

dan seterusnya.

Datang ke inti

Apa yang terjadi ketika kita melakukan bitwise AND pada angka x, yang merupakan kekuatan 2, dan x - 1?

Yang xdisejajarkan dengan nol x - 1dan semua nol xdisejajarkan dengan yang x - 1, menyebabkan bitwise DAN menghasilkan 0. Dan itulah bagaimana kita memiliki jawaban satu baris yang disebutkan di atas benar.


Lebih lanjut menambah keindahan jawaban yang diterima di atas -

Jadi, kami memiliki properti yang dapat kami miliki sekarang:

Ketika kita mengurangi 1 dari angka berapa pun, maka dalam representasi biner 1 paling kanan akan menjadi 0 dan semua nol sebelum yang paling kanan 1 sekarang akan menjadi 1

Salah satu penggunaan luar biasa dari properti ini adalah mencari tahu - Berapa banyak 1 yang hadir dalam representasi biner dari angka yang diberikan? Kode pendek dan manis untuk melakukan itu untuk bilangan bulat yang diberikan xadalah:

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

Aspek lain dari angka yang dapat dibuktikan dari konsep yang dijelaskan di atas adalah "Bisakah setiap angka positif direpresentasikan sebagai jumlah dari kekuatan 2?" .

Ya, setiap angka positif dapat direpresentasikan sebagai jumlah kekuatan 2. Untuk angka apa pun, ambil representasi binernya. Contoh: Ambil nomor 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
nama tampilan
sumber
@Michi: Apakah saya mengklaim bahwa 0 adalah angka positif? Atau kekuatan 2?
displayName
Ya, dengan menempatkan 0 sebagai contoh dan menjadikannya matematika di dalam representasi biner itu. Itu menciptakan kebingungan.
Michi
1
Jika menambahkan dua angka membingungkan Anda untuk percaya bahwa mereka harus positif, saya tidak bisa berbuat apa-apa. Selanjutnya, 0 telah ditunjukkan dalam representasi yang menyiratkan bahwa kekuatan 2 dilewati dalam angka ini. Siapa pun yang tahu matematika dasar sadar bahwa menambahkan 0 berarti tidak menambahkan apa pun.
displayName
10

Setelah memposting pertanyaan saya memikirkan solusi berikut:

Kita perlu memeriksa apakah tepat satu dari angka biner itu satu. Jadi kita cukup menggeser angka yang benar satu digit pada satu waktu, dan kembalitrue jika sama dengan 1. Jika pada titik mana pun kita datang dengan angka ganjil ( (number & 1) == 1), kita tahu hasilnya false. Ini terbukti (menggunakan tolok ukur) sedikit lebih cepat daripada metode asli untuk nilai benar (besar) dan jauh lebih cepat untuk nilai palsu atau kecil.

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

Tentu saja, solusi Greg jauh lebih baik.

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

Dan inilah algoritma umum untuk mengetahui apakah suatu angka adalah kekuatan dari nomor lain.

    bool IsPowerOf(int n,int b)
    {
        if (n > 1)
        {
            while (n % b == 0)
            {
                n /= b;
            }
        }
        return n == 1;
    }
Raz Megrelidze
sumber
6
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
kasar
sumber
1
Apakah ini c#? Saya kira ini c++seperti xdikembalikan sebagai bool.
Mariano Desanze
1
Saya memang menulisnya sebagai C ++. Untuk membuatnya C # adalah sepele: bool isPow2 = ((x & ~ (x-1)) == x)? x! = 0: false;
abelenky
4

Cari apakah angka yang diberikan adalah kekuatan 2.

#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;
}
udhaya
sumber
Atau, dalam C #: return x == Math.Pow (2, Math.Log (x, 2));
configurator
4
Rusak. Menderita masalah pembulatan titik mengambang utama. Gunakan frexpdaripada loghal - hal buruk jika Anda ingin menggunakan floating point.
R .. GitHub BERHENTI MEMBANTU ICE
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;
}
raja bug
sumber
4
int isPowerOfTwo(unsigned int x)
{
    return ((x != 0) && ((x & (~x + 1)) == x));
}

Ini sangat cepat. Diperlukan sekitar 6 menit dan 43 detik untuk memeriksa semua 2 ^ 32 bilangan bulat.

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

Jika xkekuatan dua, satu-satunya 1 bit berada di posisi n. Ini berarti x – 1memiliki 0 pada posisi n. Untuk melihat alasannya, ingat cara kerja pengurangan biner. Ketika mengurangi 1 dari x, pinjaman menyebar ke posisi n; bit nmenjadi 0 dan semua bit lebih rendah menjadi 1. Sekarang, karena xtidak memiliki 1 bit yang sama dengan x – 1, x & (x – 1)adalah 0, dan !(x & (x – 1))itu benar.

Prakash Jat
sumber
3

Angka adalah kekuatan 2 jika hanya berisi 1 set bit. Kita dapat menggunakan properti ini dan fungsi generik countSetBitsuntuk menemukan apakah angka berkekuatan 2 atau tidak.

Ini adalah program C ++:

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

Kita tidak perlu memeriksa secara eksplisit untuk 0 sebagai Kekuatan 2, karena mengembalikan False untuk 0 juga.

KELUARAN

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
jerigen
sumber
mengembalikan c sebagai 'int' ketika fungsinya memiliki jenis pengembalian 'ulong'? Menggunakan whilebukan if? Saya pribadi tidak dapat melihat alasannya, tetapi tampaknya itu akan berhasil. EDIT: - tidak ... itu akan mengembalikan 1 untuk sesuatu yang lebih besar dari 0!?
James Khoury
@ JamesKhoury Saya sedang menulis program c ++ jadi saya keliru mengembalikan int. Namun itu adalah kesalahan ketik kecil dan tidak layak downvote. Tapi saya gagal memahami alasan untuk sisa komentar Anda "menggunakan saat alih-alih jika" dan "itu akan mengembalikan 1 untuk sesuatu yang lebih besar dari 0". Saya menambahkan rintisan utama untuk memeriksa output. AFAIK adalah output yang diharapkan. Koreksi saya jika saya salah.
jerrymouse
3

Berikut adalah metode lain yang saya buat, dalam hal ini menggunakan |alih-alih &:

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));
}
Chethan
sumber
Apakah Anda perlu (x > 0)sedikit di sini?
konfigurator
@configurator, ya, jika tidak is_power_of_2 (0) akan mengembalikan true
Chethan
3

untuk kekuatan 2, yang berikut ini juga berlaku.

n & (- n) == n

CATATAN: gagal untuk n = 0, jadi perlu memeriksanya
Alasan mengapa ini bekerja adalah:
-n adalah komplemen 2s dari n. -n akan memiliki setiap bit di sebelah kiri set bit paling kanan dari n membalik dibandingkan dengan n. Untuk kekuatan 2 hanya ada satu set bit.

FReeze FRancis
sumber
2

Contoh

0000 0001    Yes
0001 0001    No

Algoritma

  1. Menggunakan bit mask, bagi NUMvariabel dalam biner

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

  3. Kalau tidak, NUMjadilah yang bukan nol

  4. IF NUM = 1: Return TRUE

  5. Jika tidak, lanjutkan ke Langkah 1

Kompleksitas

Waktu ~ di O(log(d))mana djumlah digit biner

Khaled.K
sumber
1

Meningkatkan jawaban @ user134548, tanpa aritmatika bit:

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

Ini berfungsi dengan baik untuk:

IsPowerOfTwo(9223372036854775809)
rhodan
sumber
operasi floating point jauh lebih lambat daripada ekspresi bitwise sederhana
phuclv
1

Mark gravell menyarankan ini jika Anda memiliki .NET Core 3, System.Runtime.Intrinsics.X86.Popcnt.PopCount

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

Instruksi tunggal, lebih cepat dari (x != 0) && ((x & (x - 1)) == 0)tetapi kurang portable.

jbat100
sumber
Anda yakin lebih cepat dari itu (x != 0) && ((x & (x - 1)) == 0)? Saya ragu itu, esp. pada sistem lama di mana popcnt tidak tersedia
phuclv
Itu tidak lebih cepat. Saya baru saja menguji ini pada CPU Intel modern dan memverifikasi POPCNT yang digunakan dalam pembongkaran (diberikan, dalam kode C, bukan .NET). POPCNT lebih cepat untuk menghitung bit secara umum, tetapi untuk kasus single-bit-on, trik twiddling bit masih lebih cepat 10%.
eraoul
Ups, saya ambil kembali. Saya menguji dalam satu lingkaran jika saya pikir prediksi cabang "curang". POPCNT memang merupakan instruksi tunggal yang berjalan dalam satu siklus clock tunggal dan lebih cepat jika tersedia.
eraoul
0

Di C, saya menguji i && !(i & (i - 1)trik dan membandingkannya dengan __builtin_popcount(i), menggunakan gcc di Linux, dengan flag -mpopnt untuk memastikan untuk menggunakan instruksi POPCNT CPU. Program pengujian saya menghitung # bilangan bulat antara 0 dan 2 ^ 31 yang merupakan kekuatan dua.

Pada awalnya saya pikir i && !(i & (i - 1)itu 10% lebih cepat, meskipun saya memverifikasi bahwa POPCNT digunakan dalam pembongkaran di mana saya menggunakan__builtin_popcount .

Namun, saya menyadari bahwa saya telah memasukkan pernyataan if, dan prediksi cabang mungkin lebih baik pada versi yang sedikit memutar-mutar. Saya menghapus if dan POPCNT berakhir lebih cepat, seperti yang diharapkan.

Hasil:

Intel (R) Core (TM) i7-4771 CPU maks 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-Core Processor maks 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

Perhatikan bahwa di sini CPU Intel tampaknya sedikit lebih lambat dari AMD dengan sedikit memutar-mutar, tetapi memiliki POPCNT yang jauh lebih cepat; AMD POPCNT tidak memberikan banyak dorongan.

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

Jalankan tes:

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
eraoul
sumber
0

Saya melihat banyak jawaban menyarankan untuk mengembalikan n &&! (N & (n - 1)) tetapi menurut pengalaman saya jika nilai input negatif, ia mengembalikan nilai palsu. Saya akan membagikan pendekatan sederhana lain di sini karena kita tahu kekuatan dua angka hanya memiliki satu set bit, jadi cukup kita akan menghitung jumlah bit set, ini akan membutuhkan waktu O (log N).

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

Periksa artikel ini untuk menghitung no. bit set

Anil Gupta
sumber
-1
private static bool IsPowerOfTwo(ulong x)
{
    var l = Math.Log(x, 2);
    return (l == Math.Floor(l));
}
pengguna134548
sumber
Coba itu untuk nomor 9223372036854775809. Apakah berhasil? Saya pikir tidak, karena kesalahan pembulatan.
configurator
1
@configurator 922337203685477580_9_ tidak terlihat seperti kekuatan 2 bagi saya;)
Kirschstein
1
@ Kirschstein: nomor itu memberinya positif palsu.
Erich Mirabal
7
Kirschstein: Bagi saya juga tidak seperti itu. Itu memang terlihat seperti salah satu ke fungsi ...
configurator
-2

Program ini di java mengembalikan "true" jika angka adalah kekuatan 2 dan mengembalikan "false" jika bukan kekuatan 2

// 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
K_holla
sumber
1
pertanyaan ini ditandai C #, dan solusi Anda juga sangat lambat dibandingkan dengan solusi sebelumnya [
phuclv