在C++中测试一个数字是2的幂是最简单的方法是什么?

Ant*_*Ant 86 c++ algorithm bit-manipulation

我需要一个这样的函数:

// 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);
Run Code Online (Sandbox Code Playgroud)

任何人都可以建议我怎么写这个?你能告诉我一个可以找到这种算法的好网站吗?

Ano*_*ous 171

(n & (n - 1)) == 0是最好的.但是,请注意,对于n = 0,它将错误地返回true,因此如果可能,您将需要显式检查它.

http://www.graphics.stanford.edu/~seander/bithacks.html有很多聪明的比特算法,包括这个算法.

  • 所以基本上`(n> 0 &&((n&(n-1))== 0))` (7认同)
  • @SaurabhGoyal 或 `n && !(n & (n - 1))` 作为答案中的链接。 (2认同)

Ada*_*ght 80

2的幂将只设置一位(对于无符号数).就像是

bool powerOfTwo = !(x == 0) && !(x & (x - 1));
Run Code Online (Sandbox Code Playgroud)

工作正常; 一个小于2的幂是一个在较低有效位中的1,所以必须AND到0按位.

当我假设无符号数字时,== 0测试(我原先忘了,对不起)就足够了.如果使用有符号整数,则可能需要> 0测试.


Mat*_*lls 46

二进制的两个幂看起来像这样:

1: 0001
2: 0010
4: 0100
8: 1000
Run Code Online (Sandbox Code Playgroud)

请注意,始终确实设置了1位.唯一的例外是带符号整数.例如,值为-128的8位有符号整数看起来像:

10000000
Run Code Online (Sandbox Code Playgroud)

因此,在检查数字大于零之后,我们可以使用一个聪明的小工具来测试一个并且只设置一个位.

bool is_power_of_2(int x) {
    return x > 0 && !(x & (x?1));
}
Run Code Online (Sandbox Code Playgroud)

有点麻烦,请看这里.


小智 13

方法#1:

将数字除以2以进行检查.

时间复杂度: O(log2n).

方法#2:

按位AND与前一个数字的数字应该等于ZERO.

示例: Number = 8二进制8:1 0 0 0二进制7:0 1 1 1和两个数字的按位AND为0 0 0 0 = 0.

时间复杂度: O(1).

方法#3:

按位XOR数字与其前一个数字应该是两个数字的总和.

示例: Number = 8二进制8:1 0 0 0二进制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


Rak*_*111 8

在 C++20 中std::ispow2,如果您不需要自己实现它,您可以将其用于此目的:

#include <bit>
static_assert(std::ispow2(16));
static_assert(!std::ispow2(15));
Run Code Online (Sandbox Code Playgroud)

  • 请注意,它已重命名为 [`std::has_single_bit`](https://en.cppreference.com/w/cpp/numeric/has_single_bit),并且仅针对无符号整数类型定义。对于有符号整数类型,您可能还需要检查该值是否为正,以避免错误地将最小有符号整数值(如 INT_MIN)视为 2 的幂:`(x &gt; 0) &amp;&amp; std::has_single_bit((unsigned)x)`。 (5认同)

Rob*_*lls 7

bool is_power_of_2(int i) {
    if ( i <= 0 ) {
        return 0;
    }
    return ! (i & (i-1));
}
Run Code Online (Sandbox Code Playgroud)


F10*_*PPY 7

如果使用 GCC,这可能是最快的。它只使用一个 POPCNT cpu 指令和一个比较。任何 2 的幂的二进制表示,始终只有一位设置,其他位始终为零。所以我们用 POPCNT 计算设置位的数量,如果它等于 1,这个数字就是 2 的幂。我认为没有任何可能的更快的方法。这很简单,如果你理解一次:

if(1==__builtin_popcount(n))
Run Code Online (Sandbox Code Playgroud)

  • 请注意,对于非 x86 架构,计算人口计数可能比传统检查慢。例如,在 AArch64 上,它通常需要 4 条指令:“fmov”、“cnt”、“addv”、“fmov”,其中第一个“fmov”指令将值从通用寄存器复制到 SIMD 寄存器,最后一个指令将值从通用寄存器复制到 SIMD 寄存器。 “fmov”指令将计算出的人口计数复制回通用寄存器。 (2认同)

FRe*_*cis 6

对于2的任何幂,以下条件也成立。

n&(-n)== n

注意:该条件对于n = 0时为真,尽管不是2的幂。这样做的
原因是:
-n是n的2s补码。与n相比,-n将n的最右置位的每一位的左边翻转。对于2的幂,只有一个置1位。

  • 我的意思是 n=0 的条件为真,尽管它不是 2 的幂 (2认同)