反转四分体(nybbles)以仅使用位操作获得镜像十六进制

Reverse tetrads (nybbles) to get a mirrored hex using bit manipulations only

我被赋予了一项有趣的任务来帮助某人;这里是:

Write a function to reverse tetrads in a number only using bit manipulations, constants, ~ ! * + - sizeof() << >> & ^ and |.

If, do, while, for, goto, switch etc. are not allowed, no macros, c++ functions (even compiler's intristic functions), &&, ||, ternary, and any other data types and structures, except for unsigned int.

这是我得到的,它可以工作,但它使用一个小循环,这是一个问题...

unsigned ReverseTetrads(unsigned x)
{
   unsigned reversed = x&0xF;

   while ((x >>= 4) != 0) {
      reversed <<= 4;
      reversed |= x&0xF;
   }

   return reversed;
}

示例:

0x12ABCD should be reversed to 0xDCBA21

这是我想出的:

unsigned ReverseTetrads(unsigned x)
{
   unsigned
      reversed = x&0xF,
      offsets = 0;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed <<= 4;
   x >>= 4;
   offsets += !!x;
   reversed |= x&0xF;

   reversed >>= (7 - offsets) * 4;

   return reversed;
}

完美适用于任何 unsigned int

首先使用标准位 hack 反转四分体,忽略前导零:交换顶部和底部 16 位,然后交换每 16 位中的顶部和底部字节,然后交换每个字节中的顶部和底部 nybble。

然后您可以通过检查底部 16 位、底部字节和底部 nybble 是否为零并适当移位来去除前导零(现在是尾随零)。我们可以相信 !x 在值为 0 时计算为 1,否则为 0。

unsigned int ReverseTetrads(unsigned int x)
{
    // reverse tetrads ignoring leading zeros
    x = (x << 16) | (x >> 16);
    x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff);
    x = ((x << 4) & 0xf0f0f0f0) | ((x >> 4) & 0x0f0f0f0f);

    // get rid of the leading zeros (which are now trailing zeros)
    x >>= !(x & 0x0000ffff) * 16;
    x >>= !(x & 0x000000ff) * 8;
    x >>= !(x & 0x0000000f) * 4;

    return x;
}

根据问题,* 是允许的,但如果您认为它不算作位操作,那么您可以用 x >>= !(x & 0x0000ffff) << 4; 代替 x >>= !(x & 0x0000ffff) * 16;