【问题标题】:Gray code algorithm (32 bit or less)格雷码算法(32 位或更少)
【发布时间】:2016-05-05 10:15:17
【问题描述】:

我最近遇到了格雷码,我一直在试图围绕用于将格雷码转换回二进制(32 位或更少)的有效算法陷入困境。

num = num ^ (num >> 16);
num = num ^ (num >> 8);
num = num ^ (num >> 4);
num = num ^ (num >> 2);
num = num ^ (num >> 1);

这就是我所说的代码。现在这是我的问题:

  • 这与普通代码有什么区别(右移 1 和 XOR 直到 mask == 0)?
  • 为什么专门使用 16、8、4、2、1 而不是任何其他小于 32 位的数字?
  • 如果我们反过来做有什么区别:

    num = num ^ (num >> 1);
    num = num ^ (num >> 2);
    num = num ^ (num >> 4);
    num = num ^ (num >> 8);
    num = num ^ (num >> 16);
    

    我已经试过了,它似乎产生了相同的结果。

【问题讨论】:

  • I have tried [reverse] and it seems to yield the same result. 你能证明吗? What is the difference between [shift by powers of 2] and the [basic algorithm] (right shift by 1…) 尝试更小的例子。

标签: algorithm gray-code


【解决方案1】:

例如,以位为单位(我们取 8)

h g^h f^g e^f d^e c^d b^c a^b

如果我们申请x ^= x >> 1 会发生什么?我们得到了这个

h g f^h e^g d^f c^e b^d a^c

这看起来就像我们刚开始的那样,好像它是由 x ^ (x >> 2) 而不是 x ^ (x >> 1) 制作的,所以同样的想法是只用 2 的移位来反转:

h g f e d^h c^g b^f a^e

看起来不错,现在很明显为什么x ^= x >> 4 会完全恢复正常。对于更多位,相同的模式只会持续一段时间。

另一种看待这个问题的方法是暂时反转位,将“灰色”变为x ⊗ 3 是 GF(2k) 中的乘法,乘以奇数numbers 在 GF(2k) 中是可逆的,并且 3 的乘法逆是“所有位设置”,您可以找到如下:

  • y=3 和一个临时逆向i=1 开头
  • y(不是 lsb)中的第一位与 3 进行异或运算,将相应位设置为逆向
  • 循环直到y=1

所以第一步是y=3, i=1y=5, i=3y=9, i=7 等,直到您在i 中设置所有位,让我们称之为最终i inv

然后我们有(x ⊗ 3) ⊗ inv = x ⊗ (3 ⊗ inv) = x ⊗ 1 = x

乘以“所有位设置”意味着每个位最终都是其自身和所有低位的异或,您可以这样做

x ^= x << 1
x ^= x << 2
x ^= x << 4
...

首先将所有位与它们旁边的位进行异或,然后与接下来的两个位进行异或(它们已经被异或在一起,因此只需要一步),然后是接下来的四个位,等等。

再次反转位以获得您开始的内容。

但现在有趣的东西。

为什么顺序不重要?

(是的,事实上你不仅可以颠倒这些步骤,还可以任意打乱它们)

好的,反转位并返回到 GF(2k)。写每一行的另一种方法是

x = x ⊗ 3
x = x ⊗ 5
x = x ⊗ 17
...

最终结果当然是((x ⊗ 3) ⊗ 5) ⊗ 17 = x ⊗ (3 ⊗ 5 ⊗ 17) = x ⊗ 127

GF(2k) 中的乘法非常好并且可交换,所以它可以按任何顺序完成。

其他数字呢

当然,只要他们的产品是inv。但是所有其他选择都会导致出现烦人的/许多被乘数。例如,也许我们希望 9 作为一个因数,那么剩下的就是 199,它可以分解为 9 ⊗ 63,依此类推,但这会持续一段时间,直到你可能有 3、5、9、9、17、 65,这太糟糕了(请注意,如果有 8 位,无论如何 9 ⊗ 9 ⊗ 65 = 1 所以是的,只需将其踢出并返回原始的 3、5、17)。不过有可能。

【讨论】:

  • 谢谢回复,听说1->2->4->8->16跟并行前缀计算有关系,并行前缀操作在这里起什么作用?
  • @EidolonMK 当他们以并行方式计算累积的东西时,这就是他们所说的,所以这里我们有前缀 XOR 并使用位级并行计算它
  • 有趣的事实:gray->根据twitter.com/rygorous/status/1050461906073341952,二进制解码可以用一个无进位乘法完成 - 对于__m128i vx底部的32位int,_mm_clmulepi64_si128(vx, _mm_set_epi32(0,0,1,-2), 0)产生结果在低 qword 的上半部分 - _mm_extract_epi32(prod, 1).
猜你喜欢
  • 2018-09-16
  • 1970-01-01
  • 2019-02-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 2015-10-19
  • 2010-12-14
相关资源
最近更新 更多