非常有趣的问题和巧妙的把戏。
让我们看一个简单的例子,对单个字节进行操作。为了简单起见,使用无符号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 0。特别是当这些位在原始编号中的顺序与重新排序后的顺序不同时,这是对原始标准的重要改进。例如,这意味着一个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结束于位置m, n,它的左边必须有m-1个零,而右边则需要nm个零。”
@Ternary指出,此规则不太有效,因为可能会在“目标区域的右边”添加一些进位,即当我们要查找的位全部为1时。继续上面我给出的示例,在一个16位字中使用五个紧密包装的位:如果我们以
a...e.b...d..c..
为了简单起见,我将命名位位置 ABCDEFGHIJKLMNOP
我们要做的数学是
ABCDEFGHIJKLMNOP
a000e0b000d00c00
0b000d00c0000000
000d00c000000000
00c0000000000000 +
----------------
abcded(b+c)0c0d00c00
到现在为止,我们认为下面什么abcde
(职位ABCDE
)不会有问题,但事实上,作为@Ternary指出,如果b=1, c=1, d=1
然后(b+c)
在位置G
会造成一点携带到位置F
,这意味着(d+1)
在适当的位置F
将携带位为E
-我们的结果被宠坏了。请注意,感兴趣的最低有效位右边的空间(c
在此示例中)并不重要,因为乘法将导致从最低有效位附近的零开始填充。
因此,我们需要修改(m-1)/(nm)规则。如果有一个以上的位在右侧具有“完全(nm)个未使用的位”(不计算模式的最后一位-在上面的示例中为“ c”),那么我们需要加强规则-我们必须如此反复!
我们不仅要查看满足(nm)标准的位数,而且还要查看处于(n-m + 1)n-m
位的位数,等等。让我们将它们的数量Q0(精确到下一位)称为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
;如果不起作用,请再增加一个标准,依此类推。
我认为遵循以上所述将使您获得答案的路很长...