私はこのような機能が必要です:
// 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);
誰も私がこれを書く方法を提案できますか?この種のアルゴリズムが見つかる優れたWebサイトを教えてください。
私はこのような機能が必要です:
// 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);
誰も私がこれを書く方法を提案できますか?この種のアルゴリズムが見つかる優れたWebサイトを教えてください。
回答:
(n & (n - 1)) == 0
最高です。ただし、n = 0の場合は誤ってtrueを返すため、可能であれば、明示的に確認する必要があります。
http://www.graphics.stanford.edu/~seander/bithacks.htmlには、このアルゴリズムを含む、巧妙なビット調整アルゴリズムの大規模なコレクションがあります。
(n>0 && ((n & (n-1)) == 0))
n && !(n & (n - 1))
回答状態内のリンクとして。
n & !(n & (n - 1))
。ビット単位のAND &
(論理andではない&&
)に注意してください。ビットごとの演算子は短絡を実装しないため、コードは分岐しません。これは、分岐の予測ミスが発生する可能性が高く、式のrhs(つまり!(n & (n - 1))
)を計算するのが安価な場合に適しています。
!
は論理演算子であり、したがっての値は!(n & (n - 1))
ブール値になります。ビット単位のAND演算子にブール値と数値を指定できますか?はいの場合、よさそうです。
2の累乗では、ビットが1つだけ設定されます(符号なしの数値の場合)。何かのようなもの
bool powerOfTwo = !(x == 0) && !(x & (x - 1));
正常に動作します。2の累乗よりも1小さい値は、下位ビットがすべて1であるため、ビットごとにANDする必要があります。
符号なしの数値を想定していたので、== 0のテスト(最初は忘れてしまい、申し訳ありません)で十分です。符号付き整数を使用している場合は、0より大きいテストが必要な場合があります。
アプローチ#1:
数値を2で除算して確認します。
時間の複雑さ: O(log2n)。
アプローチ#2:
ビットごとのANDと直前の数値の数値はゼロに等しくなければなりません。
例: Number = 8 Binary of 8:1 0 0 0 Binary of 7:0 1 1 1そして、両方の数値のビットごとのANDは0 0 0 0 = 0です。
時間の複雑さ: O(1)。
アプローチ#3:
直前の数値とビット単位のXORは、両方の数値の合計でなければなりません。
例: Number = 8 Binary of 8:1 0 0 0 Binary of 7:0 1 1 1そして、両方の数値のビットごとのXORは1 1 1 1 = 15です。
時間の複雑さ: O(1)。
http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html
2の累乗の場合、次のことが成り立ちます。
注:2のべき乗ではありませんが、n = 0の場合、条件はtrueです。
これが機能する理由は次のとおりです。
-nはnの2の補数です。-nは、nと比較して、nの右端の設定ビットの左側にあるすべてのビットを反転します。2の累乗の場合、設定ビットは1つだけです。
C ++ 20ではstd::ispow2
、自分で実装する必要がない場合に、まさにこの目的で使用できるものがあります。
#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));
GCCを使用している場合、これがおそらく最速です。POPCNT cpu命令と1つの比較のみを使用します。2の累乗の2進数表現は、常に1つのビットセットのみを持ち、他のビットは常に0です。したがって、POPCNTを使用して設定ビットの数を数えます。これが1に等しい場合、その数は2の累乗です。より高速な方法は考えられません。そして、それを一度理解すれば、それは非常に簡単です。
if(1==__builtin_popcount(n))
i && !(i & (i - 1)))
は、gccでネイティブアセンブリPOPCNT命令を有効にすることが確実だったとしても、私のマシンでのテストは約10%高速です。
C ++で数値が2の累乗であるかどうかをテストする最も簡単な方法は何ですか?
ビット操作命令を備えた最新のIntelプロセッサを使用している場合は、以下を実行できます。他の人がすでにそれに答えているので、ストレートC / C ++コードを省略しますが、BMIが利用できない、または有効になっていない場合は必要です。
bool IsPowerOf2_32(uint32_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
return !!((x > 0) && _blsr_u32(x));
#endif
// Fallback to C/C++ code
}
bool IsPowerOf2_64(uint64_t x)
{
#if __BMI__ || ((_MSC_VER >= 1900) && defined(__AVX2__))
return !!((x > 0) && _blsr_u64(x));
#endif
// Fallback to C/C++ code
}
GCC、ICC、およびClangは、でBMIサポートを通知し__BMI__
ます。AVX2が利用可能で有効になっている場合、Visual Studio 2015以降のMicrosoftコンパイラーで利用できます。必要なヘッダーについては、SIMD組み込みのヘッダーファイルを参照してください。
私は通常の警備_blsr_u64
で_LP64_
た場合には、i686の上でコンパイルします。Clangはわずかに異なる組み込みシンボルnamを使用するため、少しの回避策が必要です。
#if defined(__GNUC__) && defined(__BMI__)
# if defined(__clang__)
# ifndef _tzcnt_u32
# define _tzcnt_u32(x) __tzcnt_u32(x)
# endif
# ifndef _blsr_u32
# define _blsr_u32(x) __blsr_u32(x)
# endif
# ifdef __x86_64__
# ifndef _tzcnt_u64
# define _tzcnt_u64(x) __tzcnt_u64(x)
# endif
# ifndef _blsr_u64
# define _blsr_u64(x) __blsr_u64(x)
# endif
# endif // x86_64
# endif // Clang
#endif // GNUC and BMI
この種のアルゴリズムが見つかる優れたWebサイトを教えてください。
このWebサイトはよく引用されます:ビットツイドルリングハック。
これは最速でも最短でもありませんが、とても読みやすいと思います。だから私はこのようなことをします:
bool is_power_of_2(int n)
int bitCounter=0;
while(n) {
if ((n & 1) == 1) {
++bitCounter;
}
n >>= 1;
}
return (bitCounter == 1);
}
バイナリは2の累乗に基づいているため、これは機能します。1ビットのみが設定された数値は、2の累乗でなければなりません。
C ++で可能です
int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}
log2
つまり、のために確かに速くはありません。また、それが機能することを説明するのは簡単ではありません(正確には、丸めエラーに巻き込まれますか?)。また、不必要にと複雑になりif..return..else..return
ます。それを折りたたむことの何が問題になっていreturn x==(double)y;
ますか?bool
Anyayws を返す必要があります。IMOの3項演算子でさえも、本当にこだわりたい場合はより明確になりint
ます。
もう1つの方法(おそらく最速ではないかもしれません)は、ln(x)/ ln(2)が整数かどうかを判断することです。
これは、T-SQL(SQL Server)のビットシフト方式です。
SELECT CASE WHEN @X>0 AND (@X) & (@X-1)=0 THEN 1 ELSE 0 END AS IsPowerOfTwo
対数を4回行うよりもはるかに高速です(最初のセットは10進数の結果を取得するため、2番目のセットは整数のセットを取得して比較するため)