Language agnostic 给定一个整数,如何使用位旋转找到二的下一个最大幂?

Language agnostic 给定一个整数,如何使用位旋转找到二的下一个最大幂?,language-agnostic,bit-manipulation,Language Agnostic,Bit Manipulation,如果我有一个整数n,我如何才能找到下一个数k>n,这样k=2^I,通过位移位或逻辑,有I元素n 示例:如果我有n=123,我如何才能找到k=128,这是2的幂,而不是只能被2整除的124。这应该很简单,但我想不起来。这里有一个合乎逻辑的答案: function getK(int n) { int k = 1; while (k < n) k *= 2; return k; } 函数getK(int n) { int k=1; 而(k

如果我有一个整数
n
,我如何才能找到下一个数
k>n
,这样
k=2^I
,通过位移位或逻辑,有
I
元素
n

示例:如果我有
n=123
,我如何才能找到
k=128
,这是2的幂,而不是只能被2整除的
124
。这应该很简单,但我想不起来。

这里有一个合乎逻辑的答案:

function getK(int n)
{
  int k = 1;
  while (k < n)
    k *= 2;
  return k;
}
函数getK(int n) { int k=1; 而(k对于32位整数,这是一种简单而直接的方法:

unsigned int n;

n--;
n |= n >> 1;   // Divide by 2^k for consecutive doublings of k up to 32,
n |= n >> 2;   // and then or the results.
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n++;           // The result is a number of 1 bits equal to the number
               // of bits in the original number, plus 1. That's the
               // next highest power of 2.
这里有一个更具体的例子。让我们以数字221为例,它是11011101的二进制:

n--;           // 1101 1101 --> 1101 1100
n |= n >> 1;   // 1101 1100 | 0110 1110 = 1111 1110
n |= n >> 2;   // 1111 1110 | 0011 1111 = 1111 1111
n |= n >> 4;   // ...
n |= n >> 8;
n |= n >> 16;  // 1111 1111 | 1111 1111 = 1111 1111
n++;           // 1111 1111 --> 1 0000 0000
n--;           // 1000 0011 --> 1000 0010
n |= n >> 1;   // 1000 0010 | 0100 0001 = 1100 0011
n |= n >> 2;   // 1100 0011 | 0011 0000 = 1111 0011
n |= n >> 4;   // 1111 0011 | 0000 1111 = 1111 1111
n |= n >> 8;   // ... (At this point all bits are 1, so further bitwise-or
n |= n >> 16;  //      operations produce no effect.)
n++;           // 1111 1111 --> 1 0000 0000
第九位有一位,代表2^8,或256,实际上是2的次大幂。每个移位将该数字中的所有现有1位与一些先前未触及的零重叠,最终产生与原始数字中的位数相等的1位数。将该值加上1将产生新的2次方

另一个例子;我们将使用131,二进制形式为1000011:

n--;           // 1101 1101 --> 1101 1100
n |= n >> 1;   // 1101 1100 | 0110 1110 = 1111 1110
n |= n >> 2;   // 1111 1110 | 0011 1111 = 1111 1111
n |= n >> 4;   // ...
n |= n >> 8;
n |= n >> 16;  // 1111 1111 | 1111 1111 = 1111 1111
n++;           // 1111 1111 --> 1 0000 0000
n--;           // 1000 0011 --> 1000 0010
n |= n >> 1;   // 1000 0010 | 0100 0001 = 1100 0011
n |= n >> 2;   // 1100 0011 | 0011 0000 = 1111 0011
n |= n >> 4;   // 1111 0011 | 0000 1111 = 1111 1111
n |= n >> 8;   // ... (At this point all bits are 1, so further bitwise-or
n |= n >> 16;  //      operations produce no effect.)
n++;           // 1111 1111 --> 1 0000 0000
事实上,256是第二高的2次方,而不是131次方


如果用于表示整数的位数本身是2的幂,则可以继续有效地无限期地扩展此技术(例如,为64位整数添加一行)

int pot = 1;
for (int i = 0; i < 31; i++, pot <<= 1)
    if (pot >= x)
        break;
int-pot=1;

对于(int i=0;i<31;i++),pot是一种更为数学化的方法,没有循环:

public static int ByLogs(int n)
{
    double y = Math.Floor(Math.Log(n, 2));

    return (int)Math.Pow(2, y + 1);
}

这是一个没有循环但使用中间浮点的野生型

//  compute k = nextpowerof2(n)

if (n > 1) 
{
  float f = (float) n;
  unsigned int const t = 1U << ((*(unsigned int *)&f >> 23) - 0x7f);
  k = t << (t < n);
}
else k = 1;
//计算k=nextpowerof2(n)
如果(n>1)
{
浮点数f=(浮点数)n;
无符号整数常量t=1U>23)-0x7f);

k=t您只需要找到最重要的位并将其左移一次。这是一个Python实现。我认为x86有一条获取MSB的指令,但在这里,我将用纯Python实现它。一旦有了MSB,就很容易了

>>> def msb(n):
...     result = -1
...     index = 0
...     while n:
...         bit = 1 << index
...         if bit & n:
...             result = index
...             n &= ~bit
...         index += 1
...     return result
...
>>> def next_pow(n):
...     return 1 << (msb(n) + 1)
...
>>> next_pow(1)
2
>>> next_pow(2)
4
>>> next_pow(3)
4
>>> next_pow(4)
8
>>> next_pow(123)
128
>>> next_pow(222)
256
>>>
def msb(n): …结果=-1 …索引=0 …而n: …位=1>>定义下一个功率(n): …返回1>>下一个功率(1) 2. >>>下一个战俘(2) 4. >>>下一个战俘(3) 4. >>>下一个战俘(4) 8. >>>下一个战俘(123) 128 >>>下一个战俘(222) 256 >>>
实际上有一种汇编解决方案(从80386指令集开始)

您可以使用BSR(位扫描反转)指令扫描整数中的最高有效位

bsr扫描位,从 最高有效位,在 双字操作数或第二个字。 如果位均为零,则ZF为零 清除。否则,将设置ZF,并且 找到的第一组位的位索引, 在反向扫描时 方向,则加载到 目的地寄存器

(摘自:)

然后将结果与1相加

因此:


在较新的CPU中,您可以使用更快的
lzcnt
指令(也称为
repbsr
)。
lzcnt
在一个周期内完成其工作。

假设x不是负值

// n is the number
int min = (n&-n);
int nextPowerOfTwo = n+min;
int pot = Integer.highestOneBit(x);
if (pot != x) {
    pot *= 2;
}

以下是John Feminella的答案,它实现为一个循环,因此可以处理:

def下一个功率(n):
"""
返回下一个大于或等于n的2次幂
"""
n-=1#大于或等于n
移位=1
而(n+1)&n:#n+1还不是2的幂
n |=n>>移位

shift忘记这个!它使用循环

     unsigned int nextPowerOf2 ( unsigned int u)
     {
         unsigned int v = 0x80000000; // supposed 32-bit unsigned int

         if (u < v) {
            while (v > u) v = v >> 1;
         }
         return (v << 1);  // return 0 if number is too big
     }
unsigned int nextPowerOf2(unsigned int u)
{
无符号整数v=0x8000000;//假定为32位无符号整数
if(uu)v=v>>1;
}

返回(你说有点无聊

long int pow_2_ceil(long int t) {
    if (t == 0) return 1;
    if (t != (t & -t)) {
        do {
            t -= t & -t;
        } while (t != (t & -t));
        t <<= 1;
    }
    return t;
}
long int pow_2_ceil(long int t){
如果(t==0)返回1;
如果(t!=(t&-t)){
做{
t-=t&-t;
}而(t!=(t&-t));
t
private static int nextHighestPower(整数编号){
如果((数字和数字-1)==0){
返回号码;
}
否则{
整数计数=0;
while(数字!=0){
数字=数字>>1;
计数++;
}
返回1
甚至

#define nextPowerOf2(x, n)  x + (x & (n-1)) 

如果您使用GCC、MinGW或Clang:

template <typename T>
T nextPow2(T in)
{
  return (in & (T)(in - 1)) ? (1U << (sizeof(T) * 8 - __builtin_clz(in))) : in;
}
模板
T下一个路径2(T英寸)
{
返回值(in&(T)(in-1))?(1U大于/等于
以下代码段用于下一个数字k>n,以便k=2^i
(n=123=>k=128,n=128=>k=256)如OP

如果您希望2的最小幂大于或等于n,则只需在上述代码段中将
\uuuuu builtin\u clzll(n)
替换为
\uuu builtin\u clzll(n-1)

使用GCC或Clang的C++11(64位) 使用GCC或Clang的C++17(从8位到128位)
#包括
模板
constexpr T nextPowerOfTwo64(T n)
{
T clz=0;
如果constexpr(sizeof(T)64;
uint64低=(高==0)?n:-1低;
clz=_lzcnt_u64(hi)+_lzcnt_u64(lo);
}
返回T{1}用
\u BitScanForward()替换
\u内置的clzl()
  • Visual C++ 2008=>代码< >
  • icc=>用
    \u bit\u scan\u forward
  • GHC(Haskell)=>将
    内置clzl()
    替换为
    countLeadingZeros()
  • 欢迎捐款 请在评论中提出改进建议。同时为您使用的编译器或您的编程语言提出替代方案

    另见类似答案

    谢谢。但我正在寻找一种“有点搞笑”的方式。;-+1,不是OP想要的,但奇怪的是,我需要一个适合单个内联表达式的答案:
    2^(floor(log(x)/log(2))+1)
    它得到现有的值。下一部分y+1得到下一个最大的幂。@丹丹:但是如果n已经是2的幂,它会给出下一个2的幂,而不是返回n@endol
    #define nextPowerOf2(x, n)  x + (x & (n-1)) 
    
    template <typename T>
    T nextPow2(T in)
    {
      return (in & (T)(in - 1)) ? (1U << (sizeof(T) * 8 - __builtin_clz(in))) : in;
    }
    
    constexpr uint64_t nextPowerOfTwo64 (uint64_t n)
    {
        return 1ULL << (sizeof(uint64_t) * 8 - __builtin_clzll(n));
    }
    
    #include <cstdint>
    
    constexpr uint64_t nextPowerOfTwo64 (uint64_t n)
    {
        return 1ULL << (sizeof(uint64_t) * CHAR_BIT - __builtin_clzll(n));
    }
    
    #include <cstdint>
    
    template <typename T>
    constexpr T nextPowerOfTwo64 (T n)
    {
       T clz = 0;
       if constexpr (sizeof(T) <= 32)
          clz = __builtin_clzl(n); // unsigned long
       else if (sizeof(T) <= 64)
          clz = __builtin_clzll(n); // unsigned long long
       else { // See https://stackoverflow.com/a/40528716
          uint64_t hi = n >> 64;
          uint64_t lo = (hi == 0) ? n : -1ULL;
          clz = _lzcnt_u64(hi) + _lzcnt_u64(lo);
       }
       return T{1} << (CHAR_BIT * sizeof(T) - clz);
    }