【问题标题】:Round to the nearest power of two四舍五入到最接近的二的幂
【发布时间】:2011-05-22 20:57:14
【问题描述】:

对于给定的整数,是否有一个单行表达式(可能是布尔值)来获取最近的 2^n 数字?

例如:5,6,7 必须是 8。

【问题讨论】:

  • 编程语言中的“一行”?还是数学上的?
  • 这大致相当于counting leading zeros,因为您对第一个非零位感兴趣。
  • 你想用什么语言来做这个?你试过什么?
  • 在您的示例中,5 的最接近 2 的幂实际上是 4(或 2^2)。对于 6,答案是模棱两可的(可能是 2^2 或 2^3)。你能再详细说明一下这个问题吗?

标签: algorithm


【解决方案1】:

对于给定整数x的下一个二的幂

2^(int(log(x-1,2))+1)

或者(如果您没有接受 base 参数的log 函数

2^(int(log(x-1)/log(2))+1)

请注意,这不适用于 x

【讨论】:

    【解决方案2】:

    向上取整到二的下一个更高的幂:参见bit-twiddling hacks

    在 C 中:

    unsigned int v; // compute the next highest power of 2 of 32-bit v
    
    v--;
    v |= v >> 1;
    v |= v >> 2;
    v |= v >> 4;
    v |= v >> 8;
    v |= v >> 16;
    v++;
    

    【讨论】:

    • 因为它递减,然后将低于其最高有效位的所有位设置为 1,然后递增。
    • 使用有符号整数时要小心。值 > 0x4000_0000 将返回 0x8000_0000。
    • 输入值 > 0x8000_0000 将返回 0。
    • 顺便说一句,您可以在末尾右移一位以获得下一个最低的 2 次幂。
    【解决方案3】:

    由于问题的标题是“四舍五入到最接近的 2 次幂”,我认为包含该问题的解决方案也会很有用。

    int nearestPowerOfTwo(int n)
    {
        int v = n; 
    
        v--;
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16;
        v++; // next power of 2
    
        int x = v >> 1; // previous power of 2
    
        return (v - n) > (n - x) ? x : v;
    }
    

    它基本上找到两个的前一个和下一个幂,然后返回最接近的一个。

    【讨论】:

    • 先计算v然后再计算x使用x = v >> 1会不会更高效?
    • 你说的太对了。我将您的建议整合到我的回答中。谢谢
    【解决方案4】:

    这可以通过右移输入数字直到它变为 0 并保持移位计数来完成。这将给出最高有效 1 位的位置。得到这个数字的 2 次方将得到下一个最接近的 2 次方。

    public int NextPowerOf2(int number) {
        int pos = 0;
        
        while (number > 0) {
            pos++;
            number = number >> 1; 
        }
        return (int) Math.pow(2, pos);
    }
    

    【讨论】:

      【解决方案5】:

      为了在 Java 中四舍五入到最接近的 2 次方,您可以使用它。可能比其他答案中提到的小玩意要快。

      static long roundUpToPowerOfTwo(long v) {
        long i = Long.highestOneBit(v);
        return v > i ? i << 1 : i;
      }
      

      【讨论】:

      • 对于 Java,这应该是正确的答案。虽然它在底层做了同样的处理,但实现被注释为@HotSpotIntrinsicCandidate,这意味着如果架构允许,它可以被更快的本机方法替换。
      【解决方案6】:

      针对 VBA 进行了修改。 NextPowerOf2_1 似乎不起作用。所以我使用了循环方法。不过需要一个右移位运算符。

      Sub test()
          NextPowerOf2_1(31)
          NextPowerOf2_2(31)
          NextPowerOf2_1(32)
          NextPowerOf2_2(32)
      End Sub
      
      Sub NextPowerOf2_1(ByVal number As Long) ' Does not work
          Debug.Print 2 ^ (Int(Math.Log(number - 1) / Math.Log(2)) + 1)
      End Sub
      
      Sub NextPowerOf2_2(ByVal number As Long)
          Dim pos As Integer
          pos = 0
          While (number > 0)
              pos = pos + 1
              number = shr(number, 1)
          Wend
          
          Debug.Print 2 ^ pos
      End Sub
      Function shr(ByVal Value As Long, ByVal Shift As Byte) As Long
          Dim i As Byte
          shr = Value
          If Shift > 0 Then
              shr = Int(shr / (2 ^ Shift))
          End If
      End Function
      

      【讨论】:

        【解决方案7】:

        我认为您的意思是下一个最接近的 2^n 数字。您可以对模式 2 进行日志记录,然后从中确定下一个整数值。

        对于java,可以这样写:

        Math.ceil(Math.log(x)/Math.log(2))
        

        【讨论】:

        • Python 版本:from math import ceil, log; closest = lambda x: int(ceil(log(x) / log(2)))
        【解决方案8】:

        您的要求有点混乱,2 到 5 的最接近的幂是 4。如果您想要的是 2 的下一个幂,那么下面的 Mathematica 表达式可以满足您的要求想要:

        2^Ceiling[Log[2, 5]] => 8
        

        从中可以很容易地找出大多数编程语言中的单行代码。

        【讨论】:

          猜你喜欢
          • 2023-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多