用于求和异或的直接公式

时间:2010-10-14 10:52:08

标签: c++ c algorithm

我必须从1到N的异或数字,是否存在直接公式?

例如,如果N = 6然后1^2^3^4^5^6 = 7我想在不使用任何循环的情况下这样做,那么我需要一个O(1)公式(如果有的话)

12 个答案:

答案 0 :(得分:36)

您的公式为N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) )

int main()
{
    int S = 0;
    for (int N = 0; N < 50; ++N) {
        S = (S^N);
        int check = N & (N % 2 ? 0 : ~0) | ( ((N & 2)>>1) ^ (N & 1) );
        std::cout << "N = " << N << ": "  << S << ", " << check << std::endl;
        if (check != S) throw;
    }

    return 0;
}

输出:

N = 0: 0, 0             N = 1: 1, 1             N = 2: 3, 3
N = 3: 0, 0             N = 4: 4, 4             N = 5: 1, 1
N = 6: 7, 7             N = 7: 0, 0             N = 8: 8, 8
N = 9: 1, 1             N = 10: 11, 11          N = 11: 0, 0
N = 12: 12, 12          N = 13: 1, 1            N = 14: 15, 15
N = 15: 0, 0            N = 16: 16, 16          N = 17: 1, 1
N = 18: 19, 19          N = 19: 0, 0            N = 20: 20, 20
N = 21: 1, 1            N = 22: 23, 23          N = 23: 0, 0
N = 24: 24, 24          N = 25: 1, 1            N = 26: 27, 27
N = 27: 0, 0            N = 28: 28, 28          N = 29: 1, 1
N = 30: 31, 31          N = 31: 0, 0            N = 32: 32, 32
N = 33: 1, 1            N = 34: 35, 35          N = 35: 0, 0
N = 36: 36, 36          N = 37: 1, 1            N = 38: 39, 39
N = 39: 0, 0            N = 40: 40, 40          N = 41: 1, 1
N = 42: 43, 43          N = 43: 0, 0            N = 44: 44, 44
N = 45: 1, 1            N = 46: 47, 47          N = 47: 0, 0
N = 48: 48, 48          N = 49: 1, 1            N = 50: 51, 51

<强>解释

  1. 低位是低位和下位之间的XOR。

  2. 对于除低位以外的每个位,以下成立:

    • 如果N为奇数,则该位为0.
    • 如果N是偶数,那么该位等于N的对应位。
  3. 因此,对于奇数N的情况,结果总是0或1。

答案 1 :(得分:14)

修改
GSerg 已发布没有循环的公式,但由于某种原因删除了它(现在未删除)。该公式完全有效(除了一点点错误)。这是类似C ++的版本。

if n % 2 == 1 {
    result = (n % 4 == 1) ? 1 : 0;
} else {
    result = (n % 4 == 0) ? n : n + 1;
}

可以通过归纳证明它,通过4检查所有除法提醒。虽然,不知道如何在不产生输出和看到规律性的情况下提出它。

请详细解释一下您的方法。
由于每个位在xor运算中都是独立的,因此可以单独计算它们 此外,如果你查看数字0..n的第k位,它将形成一个模式。例如,以二进制形式从0到7的数字。

000
001
010
011
100
101
110
111

你看到第k位(k从0开始),有2^k个零,2^k个,然后2^k再次归零,等等。
因此,您可以为每个位计算有多少个而不实际经历从1到n的所有数字。

,对于k = 2,重复出现2^2 == 4个零和一个块。然后,

int ones = (n / 8) * 4; // full blocks
if (n % 8 >= 4) { // consider incomplete blocks in the end
    ones += n % 8 - 3;
}

答案 2 :(得分:10)

对于奇数N,结果为10(循环,N=3为0,N=5为1,{{1}为0等等。)

对于偶数N=7,结果为NN(循环,N+1为N + 1,N=2为N,N + 1对于N=4,N代表N=6等。

伪代码:

N=8

答案 3 :(得分:4)

让我们说将从1到N的所有值异或为XOR(N)的函数,然后

XOR(1) = 000 1 = 0 1 ( The 0 is the dec of bin 000)
XOR(2) = 001 1 = 1 1
XOR(3) = 000 0 = 0 0
XOR(4) = 010 0 = 2 0
XOR(5) = 000 1 = 0 1 
XOR(6) = 011 1 = 3 1
XOR(7) = 000 0 = 0 0
XOR(8) = 100 0 = 4 0
XOR(9) = 000 1 = 0 1
XOR(10)= 101 1 = 5 1
XOR(11)= 000 0 = 0 0
XOR(12)= 110 0 = 6 0

我希望你能看到这种模式。对于其他数字也应该类似。

答案 4 :(得分:3)

试试这个:

每次N为奇数时LSB都会切换,所以我们可以说

 rez & 1 == (N & 1) ^ ((N >> 1) & 1)

对于其余的位,可以观察到相同的模式。 每次BB+1N(从LSB开始)的位都不同时,应设置结果中的位B

因此,最终结果将是(包括N):rez = N ^ (N >> 1)

编辑:对不起,这是错的。正确答案:

表示奇数N:rez = (N ^ (N >> 1)) & 1

表示偶数N:rez = (N & ~1) | ((N ^ (N >> 1)) & 1)

答案 5 :(得分:2)

Alexey Malistov的精彩回答!他的公式的变体:n & 1 ? (n & 2) >> 1 ^ 1 : n | (n & 2) >> 1或等效n & 1 ? !(n & 2) : n | (n & 2) >> 1

答案 6 :(得分:2)

此方法避免使用条件F(N)=(N&((N&1)-1))|((N&1)^((N&3)>>1)

F(N)= (N&(b0-1)) | (b0^b1)

如果你看一下你得到的前几个数字的XOR:

N     |  F(N)
------+------
0001  |  0001
0010  |  0011
0011  |  0000
0100  |  0100
0101  |  0001
0110  |  0111
0111  |  0000
1000  |  1000
1001  |  0001

希望您注意到这种模式:

  

如果N mod 4 = 1而不是F(N)=1
  如果N mod 4 = 3而不是F(N)=0
  如果N mod 4 = 0而不是F(N)=N
  如果N mod 4 = 2F(N)=N,但第一位为1,那么N|1

棘手的部分是在没有条件的情况下在一个语句中得到这个解释我曾经做过的逻辑。

取N的前2位有效位:

b0b1这些是通过以下方式获得的:

b0 = N&1
b1 = N&3>>1

请注意,如果b0 == 1我们必须0所有位,但如果不是,那么除了第一位之外的所有位都保持不变。我们可以通过以下方式执行此操作:

N & (b0-1):这是因为2的补码,-1等于一个数字,所有位都设置为11-1=0所以当{{ 1}}这导致b0=1 ..所以这是函数的第一部分:

F(N)=0

现在这适用于F(N)= (N&(b0-1))... N mod 4 == 3,对于其他2个案例,我们只关注0b1b0

F(N)0

好的希望这个真相表看起来很熟悉!它是b0|b1|F(N)0 --+--+----- 1| 1| 0 0| 0| 0 1| 0| 1 0| 1| 1 。所以现在我们知道如何把最后一点放在我们的函数上:

b0 XOR b1 (b1^b0)

然后你去了,一个没有使用条件的函数。如果你想从正数a到b计算XOR,这也很有用。你可以做: F(N)=(N&(b0-1))|b0^b1

答案 7 :(得分:1)

对原始逻辑的改动最小:

int xor = 0;
for (int i = 1; i <= N; i++) {
    xor ^= i;
}

我们可以:

int xor = 0;
for (int i = N - (N % 4); i <= N; i++) {
    xor ^= i;
}

它确实有一个循环,但它需要一个恒定的时间来执行。我们遍历for循环的次数将在1到4之间变化。

答案 8 :(得分:1)

这个怎么样?

!(n&1)*n+(n%4&n%4<3)

答案 9 :(得分:1)

这适用于任何n;

没有任何问题
int xorn(unsigned int n)
{

    if (n % 4 == 0)
      return n;
   else if(n % 4 == 1)
       return 1;
   else if(n % 4 == 2)
       return n+1;
  else
       return 0;
}

答案 10 :(得分:0)

看看这个。这将解决您的问题。

https://stackoverflow.com/a/10670524/4973570

计算从1到N的XOR总和:

int ans,mod=N%4;
if(mod==0) ans=N;
else if(mod==1) ans=1;
else if(mod==2) ans=N+1;
else if(mod==3) ans=0;

答案 11 :(得分:0)

如果还有人需要它,这里简单的python解决方案:

def XorSum(L):
    res = 0        
    if (L-1)%4 == 0:
        res = L-1
    elif (L-1)%4 == 1:
        res = 1
    elif (L-1)%4 == 2:
        res = (L-1)^1
    else: #3
        res= 0
    return res