格雷码中的邻居

时间:2014-02-12 21:40:39

标签: c algorithm gray-code

我可以使用任何算法在格雷码中查找邻居吗?

对于小数字来说,编写整个表格就好了,但是如果我有一个像 010 110 这样的数字,则可以用6个数字来编写整个格雷码表。

3 个答案:

答案 0 :(得分:4)

Wikipedia无耻地复制:

/*
        The purpose of this function is to convert an unsigned
        binary number to reflected binary Gray code.

        The operator >> is shift right. The operator ^ is exclusive or.
*/
unsigned int binaryToGray(unsigned int num)
{
        return (num >> 1) ^ num;
}

/*
        The purpose of this function is to convert a reflected binary
        Gray code number to a binary number.
*/
unsigned int grayToBinary(unsigned int num)
{
    unsigned int mask;
    for (mask = num >> 1; mask != 0; mask = mask >> 1)
    {
        num = num ^ mask;
    }
    return num;
}

现在,请求的代码,使用掩码将位数限制为6:

unsigned int nextGray(unsigned int num)
{
    return binaryToGray((grayToBinary(num) + 1) & 0x3F);
}

unsigned int prevGray(unsigned int num)
{
    return binaryToGray((grayToBinary(num) - 1) & 0x3F);
}

答案 1 :(得分:3)

根据定义,任何具有单个位改变的扰动都是有效的相邻格雷码。问题是,对于六位值,有六种可能的结果,在任何单一编码中只有两种可能是正确的结果。

随着你增加单词大小,非决定论会变得更糟。

答案 2 :(得分:1)

最快的解决方案是将格雷码转换为常规二进制,获取下一个值并将值转换回格雷码。这些操作可能是最快和最简单的操作。

否则,您可以使用以下操作:

unsigned next_gray(unsigned gray)
{
    if (is_gray_odd(gray))
    {
        unsigned y = gray & -gray;
        return gray ^ (y << 1);
    }
    else
    {
        // Flip rightmost bit
        return gray ^ 1;
    }
}

如您所见,您必须知道格雷码的奇偶校验才能知道要应用哪种计算。常规格雷码的奇偶校验与其设置位数的奇偶校验相同。因此,计算is_gray_odd的公式如下:

bool is_gray_odd(unsigned gray)
{
    for (size_t i = CHAR_BIT * sizeof(int) / 2u ; i ; i >>= 1u)
    {
        gray ^= (gray >> i);
    }
    return (bool)(gray & 1u);
}

函数previous_gray将与函数next_gray相同,除了您必须反转条件。无论如何,前后转换到常规可能最终会更快。

编辑:如果你正在使用GCC或Clang,你可以使用编译器内在__builtin_parity来计算格雷码的奇偶校验(并且可能检查是否存在{{1}并且__GNUC__保持跨平台):

__clang__

如果这样做,计算下一个/上一个格雷码可能比在某些架构上来回转换格雷码更快。无论如何,如果你想要速度,你可以更好地进行基准测试。

编辑2:如果您只需要两个邻居并且您不关心哪个是前一个邻居,哪个是下一个邻居,那么您甚至不关心奇偶校验,你可以这样得到他们两个:

bool is_gray_odd(unsigned gray)
{
    return (bool) __builtin_parity(gray);
}