【问题标题】:the nth gray code第n个格雷码
【发布时间】:2026-02-05 05:10:02
【问题描述】:

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

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

我将其编码为:

int gray(int n)
{
  n--;
  return n ^ (n >> 1);
}

有人能解释一下上面的公式是如何工作的,或者可能是它的推导吗?

【问题讨论】:

  • 我想知道这里是否真的需要 n-- 。 n ^ (n>>1) 在代码从 0 开始计数时是完整的。
  • 是的,代码从 1 开始计数,否则公式中的 (n-1) 将是 n。 IMO,“第 1 个格雷码”对我来说比“第 0 个格雷码”更有意义。

标签: algorithm gray-code


【解决方案1】:

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

    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

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

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

由于异或在不同的位上给了我们 1,它证明了,什么相邻的代码只在一个位上不同,这是我们想要得到的格雷码的主要属性。

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

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

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

【讨论】:

    【解决方案2】:

    通过归纳证明。

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

    编辑:这太令人困惑了。我真正的意思是,

    gray(2*n)gray(2*n+1) 按某种顺序分别是 2*gray(n)2*gray(n)+1

    【讨论】:

      【解决方案3】:

      您所指的Wikipedia entry 以非常迂回的方式解释了这个等式。

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

      因此编码是稳定的,在 感觉一旦一个二进制数 出现在 Gn 它出现在同一个 在所有较长的列表中的位置;所以 谈论这个是有道理的 反射格雷码值 数:G(m) = 第 m 次反射 格雷码,从 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-1Gn(m) & 2^n-1 将是反射(按位反转)。

      换句话说:

      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)) 用于从零开始的格雷码。

      【讨论】:

        【解决方案4】:

        递增一个数字,当您按位查看它时,将所有尾随的 1 翻转为零,最后一个零翻转为 1。这是翻转了很多位,格雷码的目的是使其完全一致。这种转换使得所有被翻转的位上的两个数字(增量之前和之后)都相等,除了最高的位。

        之前:

        011...11
             + 1 
        ---------
        100...00
        

        之后:

        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 &gt;&gt; 1) 更容易计算,但似乎只将尾随 011..1 更改为 010..0 (即将除最高 1 之外的 1 的整个尾随块归零)和 10..0 更改为 11..0 (即翻转后面的 0 中最高的 0) 足以获得格雷码。

        【讨论】: