关于算法:第n个格雷码

the nth gray code

计算第n个格雷码的公式为:

1
2
(n-1) XOR (floor((n-1)/2))  
(Source: wikipedia)

我将其编码为:

1
2
3
4
5
int gray(int n)
{
  n--;
  return n ^ (n >> 1);
}

有人可以解释上面公式的工作原理,或者可能是它的推导吗?


如果查看二进制计数序列,则会注意到,相邻代码的最后几个位(无孔)不同,因此,如果对它们进行异或运算,则会出现几个尾随1的模式。同样,当您右移数字时,xor也将右移:(A xor B)>> N == A >> N xor B >> N。

1
2
3
4
5
6
7
8
9
10
    N                    N>>1                  gray
 0000           .        0000           .      0000           .
    | >xor = 0001             >xor = 0000           >xor = 0001
 0001          .         0000          .       0001          .
   || >xor = 0011           | >xor = 0001           >xor = 0010
 0010           .        0001           .      0011           .
    | >xor = 0001             >xor = 0000           >xor = 0001
 0011         .          0001         .        0010         .
  ||| >xor = 0111          || >xor = 0011           >xor = 0100
 0100                    0010                  0110

原始Xor结果和移位结果在单个位上有所不同(我在上面用点标记了它们)。这意味着,如果对它们进行异或运算,将获得设置了1位的模式。所以,

1
(A xor B) xor (A>>1 xor B>>1) == (A xor A>>1) xor (B xor B>>1) == gray (A) xor gray (B)

当xor给我们不同比特的1s时,证明了什么相邻代码仅在单个比特上有所不同,这就是格雷码的主要属性。

因此,为了完整起见,有待证明,可以从N的N ^(N >> 1)值恢复N:知道代码的第n位,我们可以使用xor恢复第n-1的位。

1
A_[bit n-1] = A_[bit n] xor gray(A)_[bit n-1]

从最大位开始(与0异或),因此我们可以恢复整数。


您引用的Wikipedia条目以非常circuit回的方式解释了该方程式。

但是,从此开始会有所帮助:

Therefore the coding is stable, in the
sense that once a binary number
appears in Gn it appears in the same
position in all longer lists; so it
makes sense to talk about the
reflective Gray code value of a
number: G(m) = the m-th reflecting
Gray code, counting from 0.

换句话说,Gn(m) & 2^n-1Gn-1(m & 2^n-1)~Gn-1(m & 2^n-1)。例如,G(3) & 1G(1)~G(1)。现在,我们知道,如果m大于2^n-1,则Gn(m) & 2^n-1将是反射的(按位倒数)。

换一种说法:

1
2
3
G(m, bits), k= 2^(bits - 1)
G(m, bits)= m>=k ? (k | ~G(m & (k - 1), bits - 1)) : G(m, bits - 1)
G(m, 1) = m

完整地计算数学,对于从零开始的格雷码,您得到(m ^ (m >> 1))


通过归纳证明。

提示:第1<(1<<(k+1))-1个值是第1<<(k-1)(1<个值的两倍,加上零或一。

编辑:那太令人困惑了。我的意思是

gray(2*n)gray(2*n+1)依次为2*gray(n)2*gray(n)+1


逐位查看数字时,将所有尾随的数字翻转为零,将最后的零翻转为1。这是很多翻转的地方,格雷码的目的是使其完全一致。这种转换使两个数字(递增前后)在所有被翻转的位(最高位除外)上均相等。

之前:

1
2
3
4
011...11
     + 1
---------
100...00

后:

1
2
3
4
5
6
010...00
     + 1
---------
110...00
^<--------This is the only bit that differs
          (might be flipped in both numbers by carry over from higher position)

n ^ (n >> 1)更易于计算,但似乎仅将尾随的011..1更改为010..0(即将除最高1外的整个尾随的块清零),将10..0更改为11..0(即将最高0翻转)尾随0表示)足以获得格雷码。