非常有趣的问题,巧妙的把戏。
让我们看一个处理单个字节的简单示例。为简单起见,使用无符号 8 位。想象一下你的号码是xxaxxbxx
你想要ab000000
的。
该解决方案包括两个步骤:位掩码,然后是乘法。位掩码是一个简单的 AND 操作,将不感兴趣的位变为零。在上述情况下,您的掩码将是00100100
和结果00a00b00
。
现在最困难的部分:把它变成ab......
.
乘法是一堆移位和加法运算。关键是允许溢出“移走”我们不需要的位并将我们想要的位放在正确的位置。
乘以 4( 00000100
) 会将所有内容左移 2 并得到a00b0000
。为了让b
a 向上移动,我们需要乘以 1(将 a 保持在正确的位置)+ 4(将 b 向上移动)。这个和是 5,再加上前面的 4,我们得到一个幻数 20,或00010100
。原来是00a00b00
蒙版后的;乘法给出:
000000a00b000000
00000000a00b0000 +
----------------
000000a0ab0b0000
xxxxxxxxab......
通过这种方法,您可以扩展到更大的数字和更多位。
你问的一个问题是“这可以用任意数量的比特来完成吗?” 我认为答案是“不”,除非您允许多次屏蔽操作或多次乘法。问题是“碰撞”的问题——例如上面问题中的“流浪b”。想象一下,我们需要对像xaxxbxxcx
. 按照前面的方法,你会认为我们需要 {x 2, x {1 + 4 + 16}} = x 42(哦——所有问题的答案!)。结果:
00000000a00b00c00
000000a00b00c0000
0000a00b00c000000
-----------------
0000a0ababcbc0c00
xxxxxxxxabc......
如您所见,它仍然有效,但“只是”。这里的关键是我们想要的位之间有“足够的空间”,我们可以把所有东西都挤起来。我不能在 c 之后立即添加第四位 d,因为我会得到 c+d 的实例,位可能携带,...
因此,如果没有正式的证据,我将回答您问题中更有趣的部分如下:“不,这不适用于任何位数。要提取 N 位,您需要在您想要的位之间有 (N-1) 个空格提取,或有额外的掩码乘法步骤。”
对于“位之间必须有 (N-1) 个零”规则,我能想到的唯一例外是:如果要提取原始中彼此相邻的两个位,并且要将它们保留在同样的顺序,那么你仍然可以做到。并且出于 (N-1) 规则的目的,它们计为两位。
还有另一种见解 - 受到下面@Ternary 答案的启发(请参阅我的评论)。对于每个有趣的位,您只需要它右侧的零,因为您需要空间用于需要去那里的位。而且,它需要的左侧位数与左侧的结果位数一样多。因此,如果位 b 最终位于 n 的位置 m,那么它的左侧需要有 m-1 个零,右侧需要有 nm 个零。特别是当位在原始编号中的顺序与重新排序后的顺序不同时,这是对原始标准的重要改进。这意味着,例如,一个 16 位字
a...e.b...d..c..
可以转成
abcde...........
即使 e 和 b 之间只有一个空格,d 和 c 之间只有两个空格,其他空格之间只有三个空格。N-1怎么了??在这种情况下,a...e
变成“一个块”——它们乘以 1 以在正确的位置结束,因此“我们免费获得了 e”。b 和 d 也是如此(b 需要右边三个空格,d 需要左边三个空格)。所以当我们计算幻数时,我们发现有重复:
a: << 0 ( x 1 )
b: << 5 ( x 32 )
c: << 11 ( x 2048 )
d: << 5 ( x 32 ) !! duplicate
e: << 0 ( x 1 ) !! duplicate
显然,如果您希望这些数字以不同的顺序排列,则必须将它们间隔得更远。我们可以重新制定(N-1)
规则:“如果位之间至少有 (N-1) 个空格,它将始终有效;或者,如果最终结果中的位顺序已知,那么如果位 b 最终位于n,它的左边需要有 m-1 个零,右边需要有 nm 个零。”
@Ternary 指出这条规则不太适用,因为可能有一个进位从位添加“就在目标区域的右侧” - 即,当我们正在寻找的位都是 1 时。继续我上面给出的例子,在一个 16 位字中包含五个紧凑的位:如果我们从
a...e.b...d..c..
为简单起见,我将命名位位置ABCDEFGHIJKLMNOP
我们要做的数学是
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
到目前为止,我们认为任何低于abcde
(positions ABCDE
) 的东西都无关紧要,但实际上,正如@Ternary 指出的那样,如果b=1, c=1, d=1
then (b+c)
in positionG
会导致 bit 进位到 position F
,这意味着(d+1)
in positionF
会进位E
- 而我们的结果被宠坏了。请注意,感兴趣的最低有效位(c
在此示例中)右侧的空间无关紧要,因为乘法将导致在最低有效位之外用零填充。
所以我们需要修改我们的 (m-1)/(nm) 规则。如果有不止一个位在右侧有“恰好 (nm) 个未使用的位(不包括模式中的最后一位 - 上例中的“c”),那么我们需要加强规则 - 我们必须反复这样做!
我们不仅要查看满足 (nm) 标准的位数,还要查看处于 (n-m+1) 处的位数等。让我们称它们的数为 Q0(精确n-m
到下一位),Q1 ( n-m+1),直到 Q(N-1) (n-1)。然后我们冒险携带如果
Q0 > 1
Q0 == 1 && Q1 >= 2
Q0 == 0 && Q1 >= 4
Q0 == 1 && Q1 > 1 && Q2 >=2
...
如果你看这个,你可以看到如果你写一个简单的数学表达式
W = N * Q0 + (N - 1) * Q1 + ... + Q(N-1)
结果是W > 2 * N
,那么您需要将 RHS 标准增加一位(n-m+1)
。此时,操作是安全的W < 4
;如果这不起作用,请再增加一个标准,等等。
我认为遵循上述内容将使您对答案有很长的路要走...