【问题标题】:Is there a clever way to "double up" bits in an integer?有没有一种聪明的方法可以将整数中的位“加倍”?
【发布时间】:2012-12-27 21:42:41
【问题描述】:

假设我有二进制数0b00110101

是否有一组微不足道的算术运算会产生0b0000111100110011,其中第一个字的每一位都重复两次?

是否存在这样一个微不足道的函数来重复位 3、4 或 N 次?

【问题讨论】:

  • 缺少查找表,我认为答案是:没有。无论是隐式还是显式,您都需要对输入字中的位进行解包。
  • @Nate 这只是编写二进制数并将其标记为二进制数的一种方式(类似于人们通常使用0x0000 表示十六进制数。
  • @Nate:这是一个二进制文字,我相信 c++ 支持。
  • @Mario 哦,好的,谢谢,我不熟悉,我的错。
  • INTERCAL 中编写程序并使用INTERLEAVE 运算符。

标签: c++ math binary


【解决方案1】:

看看这个文件:

https://web.archive.org/web/20140629081102/http://www-graphics.stanford.edu/~seander/bithacks.html#InterleaveBMN

它描述了两个 16 位数字的交错,将其扩展到 32 位数字是相当简单的(这会创建一个 64 位数字)。您只需将模式继续一个额外的周期。像这样:

static const unsigned long long B[] = {
    0x5555555555555555,
    0x3333333333333333,
    0x0F0F0F0F0F0F0F0F,
    0x00FF00FF00FF00FF,
    0x0000FFFF0000FFFF
};
static const unsigned int S[] = {1, 2, 4, 8, 16};

unsigned long long x; // x must initially fit inside 32 bits
unsigned long long z; // z gets the result of x interleaved with itself

x = (x | (x << S[4])) & B[4];
x = (x | (x << S[3])) & B[3];
x = (x | (x << S[2])) & B[2];
x = (x | (x << S[1])) & B[1];
x = (x | (x << S[0])) & B[0];

z = x | (x << 1);

【讨论】:

  • 我忘了回答你问题的第二部分,关于一式三份等...我相信同样的事情也适用,但在B 中使用了不同的幻数。有一个关于 SO 上的 3 值 Morton Numbers 的现有问题可能会有所帮助:stackoverflow.com/questions/1024754/…
  • 这是我怀疑存在的那种解决方案。谢谢!
【解决方案2】:

我会做一张桌子——这可能是最快的方法。

你当然可以这样做:

 int doublebits(int x)
 {
     int y = 0;
     int bit = 0;
     while(x)
     {
        if (x & 1)
            y |= 3 << bit;
        bit += 2;
        x >>= 1;
     }
     return y;
 }

对于一个 8 位数字,您最多可以向下移动 8 次,向右移动 8 次以生成新数字。

【讨论】:

  • 我认为你不需要在循环中使用 if,它应该可以通过逻辑移位,或者至少在 Assembler 中是可能的。
  • 我写了它,以便它具有合理的可读性。如果您想要速度,请使用该功能生成表格。 [我不指望现代编译器,至少 gcc 和 MS 无论如何都会生成一个分支]。
  • x &gt;&gt; 1 是一个悬空语句。你是什​​么意思?
  • 已修复.. 感谢您发现 [和缺少的空间!]
  • 可读性和聪明不需要并存。我同意表格解决方案更快,但非常难看。仅通过位操作完成的操作会吸引汇编程序极客。
【解决方案3】:

好的,这次相信找到了正确的顺序:

http://oeis.org/search?q=3%2C12%2C15%2C48&sort=&language=&go=Search

他们建议生成它的一种方法是递归:

a(2n) = 4a(n), a(2n+1) = 4a(n) + 3.

这绝不是微不足道的。

【讨论】:

    【解决方案4】:

    查看here,这些技术似乎需要 LUT 或循环。所以,我认为最优雅的方式是在计算之前设置y = x 时使用“明显方式”(链接)。

    unsigned short x;   // Interleave bits of x and y, so that all of the
    unsigned short y;   // bits of x are in the even positions and y in the odd;
    unsigned int z = 0; // z gets the resulting Morton Number.
    
    x = INPUT_PATTERN;
    y = x;
    
    for (int i = 0; i < sizeof(x) * CHAR_BIT; i++) // unroll for more speed...
    {
      z |= (x & 1U << i) << i | (y & 1U << i) << (i + 1);
    }
    

    是的,我知道这不一定是 OP 要求的“聪明”解决方案,但到目前为止,其他答案也包括循环/递归,所以为什么不试一试...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-24
      • 2020-08-28
      • 2013-12-21
      • 2015-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-02
      相关资源
      最近更新 更多