这个程序实际上如何工作?

时间:2015-02-07 02:45:31

标签: java binary bit-manipulation

我编写了一个递归方法,它将接收一个数字,并返回下一个2的幂。如果输入的数字是2的幂,它将映射到自身。这假定n> 0

static int nextPower1(int n) {
    if(n == 0) {
        System.out.println("nextPower(" + n + ") = 2");
        return 2;
    } else if(n == 1) {
        System.out.println("nextPower(" + n + ") = 1");
        return 1;
    } else {
        int lastBit = n & 1;
        int secondLastBit = (n >> 1) & 1;
        int restOfTheBits = (n >> 2);

        int result = nextPower1(restOfTheBits << 1 | secondLastBit ^ lastBit);
        return result << 1;
    }

我不知道的是,如何对最后两位进行异或,并将最后一位设置为2,返回正确的2次幂?这种按位技巧如何运作?


大编辑:

好的,我看到它出错的地方,通过更新基本案例,并将XOR更改为OR,我认为它是固定的。 我把它放在循环中进行测试。循环检查2的幂从Integer.MAX_VALUE到Integer.MAX_VALUE。它将Integer.MIN_VALUE的预期答案返回至少(1 <&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;我怀疑它是因为整数是签名的。 更新的代码:

static int nextPower2(int n) {
    if(n == 3) {
        return 4;
    } else if(n < 4) {
        return 1 << (n >> 1);
    } else {
        return nextPower(((n >> 2) << 1) | ((n >> 1) & 1) | (n & 1)) << 1;
    }
}

2 个答案:

答案 0 :(得分:1)

此代码被破坏,它总是返回错误的答案,例如1 然后是一个或多个零,然后是两个1:1011,10011等。 (因为它在递归时将配对的1&1组合成一个0,来自 这一点使它与传入的1000,10000等无法区分。)

(编辑:对于所有具有偶数1位的值,它是错误的 msb的权利。每对xor到0,失去必要的信息 为了正确的结果。 - AR。)

递归循环将最低有效位汇总到数字中 作为卷起部分是否包含任何1的历史。 隔离两个最不重要的位只会使代码更难以遵循; 它在做otherBits = n >> 1; return nextPower1(otherBits ^ lastBit)

当看最后两位时(最重要的位和 卷起历史位),如果历史为零则为最高位 是唯一的设置位,本身就是2的下一个幂。如果历史位 然而,如果是一个,那么下一个2的幂是下一个位置,一个 过了msb。 (如果只有历史记录位正常工作;见下文)

代码看起来不是最后两位,而是在汇总的结果中 msb和历史位。如果为1,则仅设置msb,历史为零,并返回1(self)作为2的幂。如果为0,则历史位为 设置,并返回下一个更高的功率(2)。随着递归的展开, 功率(1或2)移回原来的msb位置,产生 msb或下一个更强大的两个。

但是,由于历史记录不会通过零传播,因此会中断。

要修复,递归需要修复历史记录(使用OR,而不是XOR),以及 不要将历史位混合到最后的msb中,例如:

nextPower( int n ) {
    if (n == 1) return 1;
    if (n == 2) return 2;
    if (n == 3) return 4;
    return nextPower((n >> 1) | (n & 1)) << 1;
}

(测试(n == 0)支持n&gt; = 0,代码明确没有)

答案 1 :(得分:0)

按如下方式修复代码使其有效(参见http://ideone.com/P5s4rd):

import java.util.*;
import java.lang.*;
import java.io.*;

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static void main (String[] args) throws java.lang.Exception
    {
        int n;
        int result;
        for (n=0;n<=16;n++) {
            result = nextPower(n);
            System.out.println("Next power of " + n + " is " + result);
        }
    }

    static int nextPower(int n) {
        int result;
        result = nextPower1(n);
        if (n<=1 || result ==n)
            return result;
        else
            return result * 2;
    }


    static int nextPower1(int n) {
        if(n == 0) {
            return 1;
        } else if(n == 1) {
            return 1;
        } else {
            int lastBit = n & 1;
            int secondLastBit = (n >> 1) & 1;
            int restOfTheBits = (n >> 2);

            int result = nextPower1(restOfTheBits << 1 | secondLastBit ^ lastBit);
            return result << 1;
        }
    }
}

您将获得以下输出:

Next power of 0 is 1 (0 <= 2 power 0)
Next power of 1 is 1 (1 <= 2 power 0)
Next power of 2 is 2 (2 <= 2 power 1)
Next power of 3 is 4 (3 <= 2 power 2)
Next power of 4 is 4 ...etc
Next power of 5 is 8
Next power of 6 is 8
Next power of 7 is 8
Next power of 8 is 8
Next power of 9 is 16
Next power of 10 is 16
Next power of 11 is 16
Next power of 12 is 16
Next power of 13 is 16
Next power of 14 is 16
Next power of 15 is 16
Next power of 16 is 16