簡體   English   中英

如何找到小於給定數的 2 的最大冪

[英]How to find the largest power of 2 less than the given number

我需要找到小於給定數字的 2 的最大冪。
我卡住了,找不到任何解決方案。

代碼:

public class MathPow {
   public int largestPowerOf2 (int n) {
        int res = 2;        
        while (res < n) {
            res =(int) Math.pow(res, 2);
        }
        return res;
   }
}

這不能正常工作。

測試輸出:

Arguments Actual Expected
-------------------------
9         16     8       
100       256    64      
1000      65536  512     
64        256    32      

如何解決這個問題?

Integer.highestOneBit(n-1);

對於n <= 1這個問題沒有意義。 在該范圍內做什么由感興趣的讀者決定。

這是Hacker's Delight中一些很好的 bit twiddling 算法集合。

更改res =(int)Math.pow(res, 2); res *= 2; 這將返回大於 res 的下一個 2 的冪。
因此,在一段時間結束后,您正在尋找的最終結果最終將是res / 2

為了防止代碼溢出 int 值空間,您應該/可以將 res 的類型更改為 double/long,任何可以保存比 int 值更高的值。 最后,您將不得不施放一次。

你可以使用這個小技巧

v--;
v |= v >> 1;
v |= v >> 2;
v |= v >> 4;
v |= v >> 8;
v |= v >> 16;
v++;
v >>= 1;

為什么不使用日志?

public int largestPowerOf2(int n) {
    return (int)Math.pow(2, Math.floor(Math.log(n) / Math.log(2));
}

log(n) / log(2)告訴你 2 進入一個數字的次數。 通過使用它,您可以得到四舍五入的整數值。

Integer中有一個很好的函數numberOfLeadingZeros很有幫助。

有了它你可以做到

0x80000000 >>> Integer.numberOfLeadingZeros(n - 1);

n為 0 或 1 時,這會做一些奇怪的事情,但是對於這些輸入,沒有明確定義的“小於n的 2 的最大冪”。

編輯:這個答案更好

您可以消除 n 中的最低有效位,直到 n 是 2 的冪。您可以對 n 和 n-1 使用按位運算符 AND,這將消除 n 中的最低有效位,直到 n 是 2 的冪。如果最初 n 是 2 的冪,然后您要做的就是將 n 減 1。

public class MathPow{
   public int largestPowerOf2(int n){
      if((n & n-1) == 0){ //this checks if n is a power of 2
         n--; //Since n is a power of 2 we have to subtract 1
      }
      while((n & n-1) != 0){ //the while will keep on going until n is a power of 2, in which case n will only have 1 bit on which is the maximum power of 2 less than n. You could eliminate the != 0 but just for clarity I left it in
         n = n & n-1; //we will then perform the bitwise operation AND with n and n-1 to eliminate the least significant bit of n 
      }
      return n;
   }
}

解釋:

當您有一個數字 n(不是 2 的冪)時,小於 n 的最大 2 冪始終是 n 中的最高有效位。 如果數字 n 是 2 的冪,則小於 n 的最大 2 冪是 n 中唯一打開的位之前的位。

例如,如果我們有 8(2 的 3 次方),它的二進制表示是 1 0 00 粗體的 0 將是 n 之前 2 的最大冪。 既然我們知道二進制中的每個數字都代表 2 的冪,那么如果我們將 n 作為一個 2 的冪的數字,那么小於 n 的 2 的最大冪將是它之前的 2 的冪,這將是位在 n 中的唯一位之前。

對於一個不是 2 的冪也不是 0 的數字 n,我們知道在二進制表示中 n 會有不同的位,這些位只代表 2 的各種冪的和,其中最重要的是成為最重要的位。 然后我們可以推斷出 n 只是最高有效位加上一些其他位。 由於 n 以一定長度的位表示,並且最高有效位是我們可以用該位數表示的 2 的最高冪,但它也是我們可以用那么多位表示的最低數,那么我們可以得出結論最高有效位是小於 n 的 2 的最高冪,因為如果我們添加另一個位來表示下一個 2 的冪,我們將有一個大於 n 的 2 冪。

例子:

例如,如果我們有 168(二進制為 10101000),while 將取 168 並減去 1,即 167(二進制為 10100111)。 然后我們將對兩個數字進行按位與運算。 例子:

  10101000
& 10100111
------------
  10100000

我們現在有二進制數 10100000。如果我們從它減去 1 並對兩個數字使用按位與,我們得到 10000000,即 128,即 2 的 7 次方。

例子:

  10100000
& 10011111
-------------
  10000000

如果 n 原本是 2 的冪,那么我們必須從 n 中減去 1。 例如,如果 n 是 16,即二進制的 10000,我們將減去 1,得到 15,即二進制的 1111,然后將其存儲在 n 中(這就是 if 的作用)。 然后我們進入 while ,它對 n 和 n-1 執行按位運算符 AND,這將是 15(二進制 1111)和 14(二進制 1110)。

例子:

  1111
& 1110
--------
  1110

現在剩下 14。然后我們對 n 和 n-1 執行按位與運算,即 14(二進制 1110)和 13(二進制 1101)。

例子:

  1110
& 1101
---------
  1100

現在我們有 12 個,我們只需要消除最后一個最低有效位。 再次,我們然后對 n 和 n-1 執行按位 AND,即 12(二進制 1100)和 11(二進制 1011)。

例子

  1100
& 1011
--------
  1000

我們最終剩下 8,這是 2 小於 16 的最大冪。

您每次都對res進行平方,這意味着您計算2^2^2^2而不是2^k
將您的評估更改為以下內容:

int res = 2;
while (res * 2 < n) {
    res *= 2;
}

更新:

當然,你需要檢查int 的溢出,在這種情況下檢查

而 (res <= (n - 1) / 2)

似乎好多了。

public class MathPow {
   public int largestPowerOf2 (int n) {
        int res = 2;        
        while (res < n) {
                res = res * 2;
        }
        return res;
   }
}

這是我為此目的編寫的遞歸位移方法:

public static int nextPowDown(int x, int z) {
    if (x == 1)
        return z;
    return nextPowDown(x >> 1, z << 1);
} 

或更短的定義:

public static int nextPowTailRec(int x) {
    return x <= 2 ? x : nextPowTailRec(x >> 1) << 1;
}

因此,在您的 main 方法中,讓z參數始終等於1 可惜這里沒有默認參數:

System.out.println(nextPowDown(60, 1));                // prints 32
System.out.println(nextPowDown(24412, 1));             // prints 16384
System.out.println(nextPowDown(Integer.MAX_VALUE, 1)); // prints 1073741824

有點晚了但是...

(假設 32 位數字。)

n|=(n>>1);
n|=(n>>2);
n|=(n>>4);
n|=(n>>8);
n|=(n>>16);
n=n^(n>>1);

解釋:

第一 | 確保設置了原始最高位和第二高最高位。 第二 | 確保這兩個,接下來的兩個是,等等,直到你可能達到所有 32 位。 IE

100010101 -> 111111111

然后我們通過將 1 的字符串與該 1 的字符串向左移動 1 進行異或運算來移除除最高位之外的所有位,最后我們只得到最高位后跟 0 的一位。

從左到右找到第一個設置位,並使所有其他設置位為 0。

如果只有 1 個設置位,則右移一位。

我認為這是最簡單的方法。

Integer.highestOneBit(n-1);

public class MathPow
{
   public int largestPowerOf2(int n)
   {
        int res = 1;        
        while (res <= (n-1)/2)
        {
            res = res * 2;
        }

        return res;
   }
}

如果數字是整數,您可以隨時將其更改為二進制,然后找出位數。

n = (x>>>0).toString(2).length-1
p=2;
while(p<=n)
{
    p=2*p;
}
p=p/2;

如果數字是 2 的冪,那么答案是顯而易見的。 (只是位移)如果不好,那么也可以通過位移來實現。

以二進制表示找到給定數字的長度。 (二進制 13 = 1101 ;長度為 4)

then shift 2 by (4-2) // 4 是給定數字的二進制長度

下面的 java 代碼將為 BigIntegers 解決這個問題(所以基本上適用於所有數字)。

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));        

    String num = br.readLine();
    BigInteger in = new BigInteger(num);
    String temp = in.toString(2);

    System.out.println(new BigInteger("2").shiftLeft(temp.length() - 2));

我在上面看到了另一個 BigInteger 解決方案,但這實際上很慢。 如果我們要超越整數和長,更有效的方法是

BigInteger nvalue = TWO.pow(BigIntegerMath.log2(value, RoundingMode.FLOOR));

其中TWO只是BigInteger.valueOf(2L)

BigIntegerMath取自番石榴。

簡單的位操作應該可以工作

 public long largestPowerOf2 (long n)
 {      
 //check already power of two? if yes simply left shift
    if((num &(num-1))==0){
        return num>>1;
    }

  // assuming long can take 64 bits     
    for(int bits = 63; bits >= 0; bits--) {
        if((num & (1<<bits)) != 0){
            return (1<<bits);
        }
    }
    // unable to find any power of 2
    return 0;   
  }
/**
 * Find the number of bits for a given number. Let it be 'k'.
 * So the answer will be 2^k.
 */
public class Problem010 {

  public static void highestPowerOf2(int n) {
    System.out.print("The highest power of 2 less than or equal to " + n + " is ");
    int k = 0;
    while(n != 0) {
      n = n / 2;
      k++;
    }

    System.out.println(Math.pow(2, k - 1) + "\n");
  }

  public static void main(String[] args) {
    highestPowerOf2(10);
    highestPowerOf2(19);
    highestPowerOf2(32);
  }

}
if(number>=2){

    while(result < number){
        result *=2;
    }
        result = result/ 2;
     System.out.println(result);
    }

暫無
暫無

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

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