求與一個數最接近的2的N次冪
阿新 • • 發佈:2021-10-28
第一種方法
public class TestClosest2NthPower { public static void main(String[] args) { System.out.println(test(-1));//1 System.out.println(test(1));//1 System.out.println(test(-1));//1 System.out.println(test(10));//16 System.out.println(test(16));//16 System.out.println(test(Integer.MAX_VALUE));//2^30 } private static int test(int target) { //int型別最大值為(2^31)-1,所以目標能取到的最大值為2^30 int MAXIMUM = 1 << 30; if (target >= MAXIMUM) { return MAXIMUM; } int result = 1; while (result < target) { result *= 2; } return result; } }
相當於在2的0次冪和2的30次冪中的31個數中找一個最接近的數。
[2^0,2^1 ... 2^30]
第二種方法
public class TestClosest2NthPower2 { public static void main(String[] args) { System.out.println(test(-1));//1 System.out.println(test(1));//1 System.out.println(test(-1));//1 System.out.println(test(10));//16 System.out.println(test(16));//16 System.out.println(test(Integer.MAX_VALUE));//2^30 } private static int test(int target) { //int型別最大值為(2^31)-1,所以目標能取到的最大值為2^30 int MAXIMUM = 1 << 30; if (target >= MAXIMUM) { return MAXIMUM; } int temp = target - 1; temp |= temp >> 1; temp |= temp >> 2; temp |= temp >> 4; temp |= temp >> 8; temp |= temp >> 16; return (temp < 0) ? 1 : temp + 1; } }
示例分析
以129為例(可以更明顯看出效果),先減1為128,二進位制表示為
00000000 00000000 00000000 10000000
右移1位
00000000 00000000 00000000 01000000
兩者按位或
00000000 00000000 00000000 11000000
保證了前兩位都為1,以此類推可以保證第一個1及之後的所有位都為1
00000000 00000000 00000000 11111111
再加一
00000000 00000000 00000001 00000000
十進位制表示為256。
核心原理
核心原理就是將一個數減1的二進位制表示的第一個1及之後的所有位都置為1,然後加1,這樣得到的數就是2的N次冪,相當於最高位的1向左進1位,之後的所有位都置為0。
為什麼要先減1
為了相容一個數已經是2的N次冪的情況。以2的4次冪16為例,減1為15,最後操作結果還是16,如果這個數不是2的N次冪,如15,其實減不減1都可以得到正確結果16。
使用場景
ForkJoinPool的構造器中初始化workQueues的容量時就使用到了這種方法。
第三種方法
public class TestClosest2NthPower3 {
public static void main(String[] args) {
System.out.println(test(-1));//1
System.out.println(test(1));//1
System.out.println(test(-1));//1
System.out.println(test(10));//16
System.out.println(test(16));//16
System.out.println(test(Integer.MAX_VALUE));//2^30
}
private static int test(int target) {
//int型別最大值(2^31)-1,所以目標能取到的最大值為2^30
int MAXIMUM = 1 << 30;
if (target >= MAXIMUM) {
return MAXIMUM;
}
int n = -1 >>> Integer.numberOfLeadingZeros(target - 1);
return (n < 0) ? 1 : n + 1;
}
}
示例分析
以129為例(可以更明顯看出效果),先減1為128,二進位制表示為
00000000 00000000 00000000 10000000
使用Integer的numberOfLeadingZeros()方法求出前導0的個數為24,-1的二進位制表示為
11111111 11111111 11111111 11111111
無符號右移24位
00000000 00000000 00000000 11111111
再加一
00000000 00000000 00000001 00000000
十進位制表示為256。
核心原理
和上一個方法的原理類似,也是將一個數減1的二進位制表示的第一個1及之後的所有位都置為1,然後加1。
使用場景
這種方法參考的就是HashMap中計算容量大小的演算法。