繁体   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