第一種方法
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中計算容量大小的算法。