更短的计算版本

时间:2016-10-19 11:31:45

标签: java algorithm math

我有两种方法,我认为可以采用更好的方法,但无法找到这种方法。

首先:

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");
}

我相信,有些方法可以在没有循环的情况下做同样的事情。你能帮忙吗?

干杯!

3 个答案:

答案 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));
}

suggested by harold

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