【问题标题】:Swapping pair of bits in a Byte交换字节中的一对位
【发布时间】:2010-09-21 08:10:20
【问题描述】:

我有一个任意的 8 位二进制 数字,例如 11101101

我必须交换所有的位,例如:

交换前:11-10-11-01 交换后:11-01-11-10

我在一次采访中被问到这个问题!

【问题讨论】:

  • 对不起,如果它让您感到困惑,我给出的第一个答案。我完全阅读了你之前/之后的错误。
  • @JamesM:对不起,如果它不明显,但问题是:在一个字节中,将位配对,例如,如果字节是 10101100,那么配对位将看起来像 - 10 - 10 - 11 - 00。现在,如果我们交换单个对,它将变为 -01 - 01 - 11 - 00。我需要实现交换的机制

标签: bit-manipulation


【解决方案1】:

在伪代码中:

x = ((x & 0b10101010) >> 1) | ((x & 0b01010101) << 1)

它的工作原理是分别处理每个位对的低位和高位,然后组合结果:

  • 表达式x &amp; 0b10101010 从每一对中提取高位,然后&gt;&gt; 1 将其移至低位。
  • 类似地,表达式(x &amp; 0b01010101) &lt;&lt; 1 从每一对中提取低位并将其移至高位位置。
  • 然后使用按位或组合这两个部分。

由于并非所有语言都允许您直接编写二进制文字,因此您可以将它们写入例如十六进制:

二进制 十六进制 十进制 0b10101010 0xaa 170 0b01010101 0x55 85

【讨论】:

  • 鉴于并非所有语言都尊重模式 0b...,可能值得注意的是它分别是 0xAA 和 0x55 十六进制。
  • @userx: +1 是的,这绝对值得注意。已添加。
  • 谢谢马克。这方法真棒!
【解决方案2】:
  1. 制作两个位掩码,一个包含所有偶数位,一个包含奇数位(1010101001010101)。
  2. 使用按位-and 将输入过滤为两个数字,一个将所有偶数位归零,另一个将所有奇数位归零。
  3. 仅包含偶数位的数字向左移动一位,另一位向右移动一位
  4. 使用按位或将它们重新组合在一起。

16 位示例(不是实际代码):

short swap_bit_pair(short i) {
    return ((i & 0101010110101010b) >> 1) | ((i & 0x0101010101010101b) << 1));
}

【讨论】:

  • 嗯..我认为您的意思是 0xAA 而不是 0x10101010(0xAA 是二进制的 10101010)和 0x55 而不是 0x01010101。无论如何,一个字节。 0xAAAA 和 0x5555 分别为短。
  • 是的,已经编辑了类似 C 的伪代码以使用二进制文件。原来的问题无论如何都是 8 位,所以......
【解决方案3】:
b = (a & 170 >> 1) | (a & 85 << 1)

【讨论】:

  • 这是完全不可读的;此外,对于边缘情况,它效率低下甚至不正确。除以 2 不等于负数的一位右移。
【解决方案4】:

正如其他人所说,最优雅和灵活的解决方案是分别对偶数位和奇数位应用“梳状”掩码,然后将它们分别向左和向右移动一个位置以使用按位或组合它们。

您可能想要考虑的另一种解决方案利用了相对较小的数据类型。您可以创建一个包含 256 个值的查找表,该表静态初始化为您想要作为输入输出的值:

const unsigned char lookup[] = { 0x02, 0x01, 0x03, 0x08, 0x0A, 0x09, 0x0B ...

每个值都放在数组中,表示索引的变换。所以如果你这样做:

unsigned char out = lookup[ 0xAA ];

out 将包含0x55

这比第一种方法更麻烦、更不灵活(如果您想从 8 位移动到 16 位怎么办?),但确实有一种方法,如果执行大量此类操作,它会明显更快。

【讨论】:

    【解决方案5】:

    假设你的号码是num

    先找到偶数位:
    num &amp; oxAAAAAAAA

    第二步找奇数位位:
    num &amp; ox55555555

    第三步将位置奇数位更改为偶数位,偶数位更改为奇数位:
    Even = (num &amp; oxAAAAAAAA)&gt;&gt;1
    Odd = (num &amp; 0x55555555)&lt;&lt;1

    最后一步...result = Even | Odd

    打印结果

    【讨论】:

      【解决方案6】:

      我会首先将其编码为“普通”——也就是说,在几个明显的、明确的阶段,并用它来验证我所进行的单元测试是否正常运行,然后只转向更深奥的位操作解决方案如果我需要表现(并且上述改进提供了额外的表现)

      首先为人编写代码,其次才是计算机。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-02-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多