web-dev-qa-db-ja.com

数が2のべき乗かどうかを調べる方法

今日私は数が2のべき乗であるかどうかをチェックするための簡単なアルゴリズムが必要でした。

アルゴリズムは次のようになります。

  1. 単純な
  2. ulong値を修正してください。

私はこの簡単なアルゴリズムを思いついた。

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

しかし、log2 xが正確に丸められた数であるかどうかをチェックするのはどうでしょうか。しかし、2 ^ 63 + 1をチェックしたとき、丸めのためMath.Logは正確に63を返しました。 2の63乗が元の数と等しいかどうかをチェックしました。正確な数ではなくdoublesで計算されるためです。

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

これは、与えられた間違った値9223372036854775809に対してtrueを返しました。

より良いアルゴリズムはありますか?

533
configurator

この問題には簡単なトリックがあります。

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

この関数は0に対してtrueを報告しますが、これは2の累乗ではありません。それを除外したい場合は、次のようにします。

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

説明

何よりもまず、MSDNの定義によるビット単位の二項演算子です。

二項演算子と演算子は、整数型とboolに対して事前定義されています。整数型の場合、&はそのオペランドの論理ビットごとのANDを計算します。 boolオペランドの場合、&はそのオペランドの論理積を計算します。つまり、両方のオペランドが真の場合に限り、結果は真になります。

それでは、これらすべてがどのように行われるのかを見てみましょう。

この関数はブール値(true/false)を返し、unsigned long型(この場合はx)の入力パラメータを1つ受け入れます。説明を簡単にするために、誰かが値4を渡して次のように関数を呼び出したとします。

bool b = IsPowerOfTwo(4)

今度は、xの各出現を4に置き換えます。

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

4!= 0が真になることはすでにわかっています。しかし、どうですか?

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

これはもちろんこれに変換されます。

((4 & 3) == 0)

しかし4&3は正確には何ですか?

4の2進数表現は100、3の2進数表現は011です(&はこれらの数の2進数表現を取ります)。だから我々は持っています:

100 = 4
011 = 3

これらの値が基本的な加算のように積み上げられていると想像してください。 &演算子は、両方の値が1の場合、結果は1になり、それ以外の場合は0になります。したがって、1 & 1 = 11 & 0 = 00 & 0 = 0、および0 & 1 = 0。だから我々は数学を行います:

100
011
----
000

結果は単に0です。それでは戻り、returnステートメントが次に何に変換されるのかを調べます。

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

これは次のようになります。

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

true && trueは単にtrueであることを私たち全員が知っています、そしてこれは私たちの例では4が2のべき乗であることを示しています。

1128
Greg Hewgill

これと他のちょっといじるハックを文書化して説明するいくつかのサイトは以下のとおりです。

そして、彼らのおじいちゃん、 Henry Warren、Jrによる "Hacker's Delight"

Sean Andersonのページ で説明されているように、式((x & (x - 1)) == 0)は誤って0が2のべき乗であることを示しています。

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

その問題を解決するために。

93
Michael Burr

return (i & -i) == i

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

私は最近 http://www.exploringbinary.com/ten-ways-to-check-if-an-integer-is-a-power-of-twoでこれについての記事を書いた-in-c / ビットカウント、対数の正しい使い方、古典的な "x &&!(x&(x - 1))"チェックなどについて説明しています。

20
Rick Regan

これは簡単な C++ の解決策です:

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

そして、ある数が別の数のべき乗であるかどうかを調べるための一般的なアルゴリズムがあります。

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

質問を投稿した後、私は以下の解決策を考えました:

2進数の1つが1であるかどうかを確認する必要があります。そのため、数値を1桁ずつ右にシフトし、1に等しい場合はtrueを返します。いずれかの時点で奇数((number & 1) == 1)が返された場合、結果はfalseです。これは(ベンチマークを使用して)(大きな)真の値の場合の元の方法よりもわずかに速く、偽または小さな値の場合のほうがはるかに速いことが証明されました。

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

もちろん、Gregの解決策ははるかに優れています。

10
configurator

次のような、受け入れられた回答の補足は、一部の人にとって役立つことがあります。

2の累乗は、2進数で表現すると、常に1の後にn個のゼロが続くように見えます。nは0以上です。例:

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

等々。

これらの種類の数から1を引くと、それらは0の後にn個の1が続き、再びnは上記と同じになります。例:

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

等々。

核心に来る

2のべき乗であるxx - 1のビットごとの論理積をとるとどうなりますか?

xの1つはx - 1のゼロと揃えられ、xのすべてのゼロはx - 1の1と揃えられ、ビットごとのANDの結果は0になります。上記の単一行の回答は正しいです。


上記の受け入れられた答えの美しさにさらに追加 -

だから、私たちは今私たちの処分で財産を持っています:

任意の数から1を引くと、バイナリ表現では右端の1が0になり、その右端の1より前のすべてのゼロが1になります。

このプロパティの素晴らしい用途の1つは、 - を調べることです。与えられた数値のバイナリ表現には1がいくつ含まれていますか?短く簡単なコード与えられた整数に対するxは次のようになります。

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

上で説明した概念から証明できる数値のもう1つの側面は、「すべての正数を2のべき乗の和として表すことができるかどうか」です

はい、すべての正数は2のべき乗の合計として表すことができます。任意の数に対して、そのバイナリ表現を取ります。例:番号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
9
displayName
bool isPow2 = ((x & ~(x-1))==x)? !!x : 0;
6
abelenky
return ((x != 0) && !(x & (x - 1)));

xが2の累乗の場合、その唯一の1ビットはnの位置にあります。これはx – 1n位置に0があることを意味します。その理由を確認するために、バイナリ減算がどのように機能するかを思い出してください。 xから1を引くと、借用はnの位置まで続きます。 bit nは0になり、すべての下位ビットは1になります。これで、xx – 1と共通の1ビットを持たないので、x & (x – 1)は0で、!(x & (x – 1))は真です。

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

これは本当に速いです。 2 ^ 32の整数すべてをチェックするのに約6分43秒かかります。

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

与えられた数が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;
}
4
udhaya

これが私が考案した別の方法です。この場合は|の代わりに&を使います。

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

セットビットが1つしかない場合、その数は2の累乗です。このプロパティと総称関数countSetBitsを使って、数値が2のべき乗かどうかを調べることができます。

これは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;
}

0は2のべき乗であることを明示的にチェックする必要はありません。0についてもFalseが返されるためです。

OUTPUT

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

2のべき乗であれば、以下も成り立ちます。

n&( - n)== n

注:n = 0の場合は失敗するので、確認する必要があります。
これが機能する理由は次のとおりです。
- nは、nの2の補数です。 -nは、nに比べてnの右端の設定ビットの左側にあるすべてのビットを反転します。 2のべき乗の場合、設定ビットは1つだけです。

2
FReeze FRancis

ビット演算なしで、@ user134548の答えを改善します。

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

これはうまくいきます:

IsPowerOfTwo(9223372036854775809)
2
rhodan

0000 0001    Yes
0001 0001    No

アルゴリズム

  1. ビットマスクを使用して、変数をNUMでバイナリに分割します

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

  3. そうでなければ、NUMはゼロ以外のものになります。

  4. IF NUM = 1: Return TRUE

  5. それ以外の場合は、手順1に進みます。

複雑さ

Time〜O(log(d))ここでdは2進数の桁数です

2
Khaled.K

Javaのこのプログラムは、numberが2のべき乗である場合は「true」を返し、2のべき乗でない場合は「false」を返します。

// 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

return i> 0 &&(i ^ -i)==(-i << 1);

そのような答えが見つかりませんでした。それを私のものにしましょう

0
Aliaksei Yatsau