我有两种方法,我认为可以采用更好的方法,但无法找到这种方法。
首先:
public int calcPow(long num) {
int count = 0;
while(num/2!=0) {
num = num/2;
count++;
}
return count;
}
第二个是:
private long findParentNumber(long value) {
for(int bitNum = 0; bitNum < Long.SIZE; bitNum++) {
if((value & (1L << bitNum)) != 0) {
return value ^ (1L << bitNum);
}
}
throw new RuntimeException("No parent number found");
}
我相信,有些方法可以在没有循环的情况下做同样的事情。你能帮忙吗?
干杯!
答案 0 :(得分:4)
对于第二个,您将取消设置最低设置位。有一个相对众所周知的bithack要做到这一点,虽然只是因为看起来一般的bithack不是众所周知。
无论如何,这是
return x & (x - 1);
这里的逻辑是,在x - 1
中,有一个借用运行最低的零,直到它达到最低的1位,它取消设置。保留最低的零,然后通过与原始数字进行AND运算将它们删除。
你可以用numberOfLeadingZeros
来写第一个,这比浮点黑客更明显是正确的,它总能让你思考它们的准确程度(无论如何它们很慢,你可能会更好的循环)。
编辑:为了完整性,这将是63 - numberOfLeadingZeros(x)
,它与您在x = 0
的定义不同,但无论如何这都是错误的输入。
答案 1 :(得分:3)
尝试第一个。
public int calcPow(long num) {
if (num == 0) return 0;
if (num < 0) num = -num;
return Long.numberOfTrailingZeros(Long.highestOneBit(num));
}
public int calcPow(long num) {
return num == 0 ? 0
: 63 - Long.numberOfLeadingZeros(Math.abs(num));
}
答案 2 :(得分:2)
对于第一个,您可以使用已存在的Math.log
方法:
public static int log2(long number) {
return (int) Math.floor(Math.log(number) / Math.log(2));
}
或更快的功能suggested by saka1029:
public static int log2(long number) {
return number == 0? 0: Long.numberOfTrailingZeros(Long.highestOneBit((number < 0)? number * -1: number));
}
正如您所看到的,我还将方法更改为静态,因为我认为在没有涉及对象时必须使用Object来获取日志。其次,我把名字改成了更合适的东西。
对于第二个,您可以使用逐位检查运算符&
:
public static long removeSmallBit(long value) {
return value & (value - 1);
}
基本上你是从变量中删除最小的位,并在将该位更改为0后返回该数字。正如您可以再次看到的那样,我将方法设为静态并更改了名称。第2回答的灵感来自this answer submitted by harold