简体   繁体   English

该程序实际上如何工作?

[英]How does this program actually work?

I wrote a recursive method that will take in a number, and return the next power of two. 我写了一个递归方法,该方法将接受一个数字,并返回下一个2的幂。 If the number entered is a power of two, it will map to itself. 如果输入的数字是2的幂,它将映射到其自身。 This presumes n > 0 假设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;
    }

What I don't get is how does XORing the last two bits and settting the second last bit return the correct power of two? 我没有得到的是如何对后两位进行异或并设置后一位为第二的正确幂? How does this bitwise trick work? 这个按位技巧如何工作?


BIG EDIT: 大编辑:

Ok, I see where it was going wrong, and by updating the base cases, and changing XOR to OR, I think it is fixed. 好的,我知道问题出在哪里,并且通过更新基本案例并将XOR更改为OR,我认为它是固定的。 I put it in a loop to test it. 我将其循环测试。 The loop checked powers of 2 from to Integer.MAX_VALUE to Integer.MAX_VALUE. 循环检查从到Integer.MAX_VALUE到Integer.MAX_VALUE的2的幂。 It returned the expected answer from Integer.MIN_VALUE up to at least (1 << 30), though it breaks after that. 它从Integer.MIN_VALUE返回期望的答案,至少达到(1 << 30),尽管此后会中断。 I suspect its because integers are signed. 我怀疑是因为整数是有符号的。 The updated code: 更新的代码:

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

this code is broken, it always returns the wrong answer for eg a 1 followed by one or more zeroes followed by two 1's: 1011, 10011, etc. (because as it recurses it combines the paired 1's into a 0, which from that point on makes it indistinguishable from an incoming 1000, 10000, etc.) 此代码已损坏,它总是返回错误的答案,例如1,后跟一个或多个零,后跟两个1:1011、10011,等等。(因为它递归,所以将成对的1组合成0,从那时开始使其与传入的1000、10000等无法区分)。

(Edit: it's wrong for all values that have an even number of 1 bits to the right of the msb. Every pair xor's to 0, losing information necessary for a correct result. - AR.) (编辑:对于msb右边具有偶数1位的所有值,这都是错误的。每一对xor都等于0,丢失了获得正确结果所需的信息。-AR。)

The recursive loop is rolling up the least significant bit into the number as a kind of history of whether the rolled-up portion contained any 1's. 递归循环将最低有效位累加到数字中,作为累加部分是否包含任何1的历史记录。 Isolating both least signficant bits just makes the code harder to follow; 隔离两个最低有效位只会使代码难以遵循。 it's doing otherBits = n >> 1; return nextPower1(otherBits ^ lastBit) 它正在执行otherBits = n >> 1; return nextPower1(otherBits ^ lastBit) otherBits = n >> 1; return nextPower1(otherBits ^ lastBit)

When looking at the last two bits left (the most signficant bit and the rolled up history bit), if the history is zero then the most significant bit is the only set bit, and itself is the next power of 2. If the history bit is one, however, then the next power of two is the next bit position, one past the msb. 当查看剩下的最后两位(最高有效位和汇总的历史位)时,如果历史为零,那么最高有效位是唯一的置位位,其本身为下一位2。如果历史位如果为1,则下一个2的幂是下一个位的位置,该位比msb大。 (if only the history bit worked correctly; see below) (如果只有历史记录位正常工作;请参见下文)

The code looks not at the last two bits, but at the rolled up result of the msb and the history bit. 该代码不是查看最后两位,而是查看msb和历史记录位的汇总结果。 If 1, then only the msb was set, history is zero, and returns 1 (self) as the power of two. 如果为1,则仅设置了msb,历史记录为零,并返回1(自身)为2的幂。 If 0, then the history bit was set, and returns the next higher power (2). 如果为0,则将历史位置1,并返回下一个更高的功率(2)。 As the recursion unwinds, the power (1 or 2) is shifted back to the original msb position, yielding the msb or the next bigger power of two. 随着递归的结束,幂(1或2)将移回到原始msb位置,从而产生msb或下一个更大的2的幂。

However, because the history does not propagate through zeros, this breaks. 但是,由于历史记录不会通过零传播,因此会中断。

To fix, the recursion would need to fix the history (use OR, not XOR), and not blend the history bit into the msb at the end, something like: 要修复,递归将需要修复历史记录(使用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;
}

(test for (n==0) to support n >= 0, which the code explicitly does not) (测试(n == 0)以支持n> = 0,该代码明确不支持)

Fixing the code as follows makes it work (See http://ideone.com/P5s4rd ): 如下修复代码即可正常工作(请参见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;
        }
    }
}

You get the following output: 您将获得以下输出:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM