簡體   English   中英

在 C++ 中測試一個數字是否是 2 的冪的最簡單方法是什么?

[英]What's the simplest way to test whether a number is a power of 2 in C++?

我需要這樣的功能:

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

誰能建議我怎么寫這個? 你能告訴我一個可以找到這種算法的好網站嗎?

(n & (n - 1)) == 0是最好的。 但是,請注意,當 n=0 時它會錯誤地返回 true,因此如果可能,您需要明確檢查它。

http://www.graphics.stanford.edu/~seander/bithacks.html有大量巧妙的位旋轉算法,包括這個。

2 的冪將只設置一位(對於無符號數)。 就像是

bool powerOfTwo = !(x == 0) && !(x & (x - 1));

會正常工作; 一個小於 2 的冪在較低有效位中全為 1,因此必須 AND 到 0 按位。

當我假設無符號數字時, == 0 測試(我最初忘記了,抱歉)就足夠了。 如果您使用有符號整數,您可能需要 > 0 測試。

二進制中的 2 次冪如下所示:

1: 0001
2: 0010
4: 0100
8: 1000

請注意,始終只設置 1 位。 唯一的例外是帶符號整數。 例如,值為 -128 的 8 位有符號整數如下所示:

10000000

因此,在檢查該數字大於零之后,我們可以使用巧妙的一點點技巧來測試是否設置了一位且僅設置了一位。

bool is_power_of_2(int x) {
    return x > 0 && !(x & (x−1));
}

欲了解更多信息,請參見此處

方法#1:

將數字除以 2 以進行檢查。

時間復雜度: O(log2n)。

方法#2:

按位 AND 與前一個數字的數字應該等於零。

示例: Number = 8 8 的二進制:1 0 0 0 7 的二進制:0 1 1 1 並且兩個數字的按位與是 0 0 0 0 = 0。

時間復雜度: O(1)。

方法#3:

按位異或數字與其前一個數字應該是兩個數字的總和。

示例: Number = 8 Binary of 8: 1 0 0 0 Binary of 7: 0 1 1 1 兩個數字的按位異或為 1 1 1 1 = 15。

時間復雜度: O(1)。

http://javaexplorer03.blogspot.in/2016/01/how-to-check-number-is-power-of-two.html

bool is_power_of_2(int i) {
    if ( i <= 0 ) {
        return 0;
    }
    return ! (i & (i-1));
}

在 C++20 中有std::ispow2 ,如果您不需要自己實現它,您可以將其用於此目的:

#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));

對於任何 2 的冪,以下也成立。

n&(-n)==n

注意:條件對 n=0 成立,盡管它不是 2 的冪。
這樣做的原因是:
-n 是 n 的 2s 補碼。 -n 將使 n 的最右側設置位左側的每一位與 n 相比翻轉。 對於 2 的冪,只有一個設置位。

如果使用 GCC,這可能是最快的。 它只使用一個 POPCNT cpu 指令和一個比較。 任何 2 的冪的二進制表示,始終只有一位設置,其他位始終為零。 所以我們用 POPCNT 計算設置位的數量,如果它等於 1,這個數字就是 2 的冪。我認為沒有任何可能的更快的方法。 這很簡單,如果你理解一次:

if(1==__builtin_popcount(n))

由於布爾短路和比較緩慢的事實,以下將比大多數投票的答案更快。

int isPowerOfTwo(unsigned int x)
{
  return x && !(x & (x – 1));
}

如果你知道 x 不能為 0 那么

int isPowerOfTwo(unsigned int x)
{
  return !(x & (x – 1));
}

在 C++ 中測試一個數字是否是 2 的冪的最簡單方法是什么?

如果您擁有帶有Bit Manipulation Instructions的現代英特爾處理器,那么您可以執行以下操作。 它省略了直接的 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
}

__BMI__支持 GCC、ICC 和 Clang 信號 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

你能告訴我一個可以找到這種算法的好網站嗎?

這個網站經常被引用: Bit Twiddling Hacks

return n > 0 && 0 == (1 << 30) % n;

這不是最快或最短的方式,但我認為它非常易讀。 所以我會做這樣的事情:

bool is_power_of_2(int n)
  int bitCounter=0;
  while(n) {
    if ((n & 1) == 1) {
      ++bitCounter;
    }
    n >>= 1;
  }
  return (bitCounter == 1);
}

這是有效的,因為二進制基於 2 的冪。 任何只有一位設置的數字必須是 2 的冪。

這是另一種方法,在這種情況下使用| 而不是&

bool is_power_of_2(int x) {
    return x > 0 && (x<<1 == (x|(x-1)) +1));
}

可以通過 C++

int IsPowOf2(int z) {
double x=log2(z);
int y=x;
if (x==(double)y)
return 1;
else
return 0;
}

我知道這是一個老的帖子,但我認為在這里發布這個帖子會很有趣。


來自Code-Golf SE (所以都歸功於寫這篇文章的人): 語言展示

(關於C 的段落,分段長度 36 片段

bool is_pow_of_2(const unsigned long long &num){return!!num&!(num&(num-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

它比做四次對數要快得多(第一組得到十進制結果,第二組得到整數集和比較)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM