如果之前已经被问过/回答过,我很抱歉,但老实说我甚至不确定如何正确地说出这个问题。我有以下位模式:
0110110110110110110110110110110110110110110110110110110110110110
我试图进行一次保留我的基本模式的转变;我的第一直觉是使用正确的旋转((x >> count) | (x << (-count & 63)))
,但我的位模式的不对称导致:
0011011011011011011011011011011011011011011011011011011011011011
&lt; ---错误
问题是最重要的(最左边)位最终为0而不是所需的1:
1011011011011011011011011011011011011011011011011011011011011011
&lt; --- right
我正在寻找这个函数的口语名称吗?如果没有,我怎么能实现这个想法呢?
其他信息:
n - 1
个(其中n
是奇数),然后无限重复。答案 0 :(得分:2)
你的数字结构如下:
B16 B15 B14 B13 B12 B11 B10 B09 B08 B07 B06 B05 B04 B03 B02 B01 B00
? 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
?
需要在班次后出现在MSB(B15,或B63,或其他)中。它从何而来?好吧,找到最近的副本n
位于右侧:
B13 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
^--------------/
如果您的字词宽度为w
,则为1 << (w-n)
*
所以你可以这样做:
var selector = 1 << (w-n);
var rotated = (val >> 1) | ((val & selector) << (n-1));
但你可能想要多班。然后我们需要建立一个更宽的面具:
? 0 1 1 0 1 1 0 1 1 0 1 1 0 1 1 0
* * * * *
在这里,我选择假装n = 6
,它只需要是基本n
的倍数,并且大于shift
。现在:
var selector = ((1UL << shift) - 1) << (w - n);
var rotated = (val >> shift) | ((val & selector) << (n - shift));
使用您的模式进行演示:http://rextester.com/UWYSW47054
根据需要,很容易看到输出具有句点3:
1:B6DB6DB6DB6DB6DB 2:DB6DB6DB6DB6DB6D 3:6DB6DB6DB6DB6DB6 4:B6DB6DB6DB6DB6DB 5:DB6DB6DB6DB6DB6D 6:6DB6DB6DB6DB6DB6 7:B6DB6DB6DB6DB6DB 8:DB6DB6DB6DB6DB6D 9:6DB6DB6DB6DB6DB6 10:B6DB6DB6DB6DB6DB 11:DB6DB6DB6DB6DB6D
答案 1 :(得分:1)
无网点答案:
原始答案:
答案 2 :(得分:1)
不要存储大量重复的模式,只需存储一次重复并对索引应用模运算
byte[] pattern = new byte[] { 0, 1, 1 };
// Get a "bit" at index "i", shifted right by "shift"
byte bit = pattern[(i - shift + 1000000 * byte.Length) % byte.Length];
+ 1000000 * byte.Length
必须大于预期的最大转变,并确保我们得到一个有效的总和。
这使您可以存储几乎任何长度的图案。
优化将是存储模式的镜像版本。然后你可以左移而不是右移。这将简化指数计算
byte bit = pattern[(i + shift) % byte.Length];
答案 3 :(得分:1)
问题在评论中有所改变。
对于所有合理的n
,在最小的预计算之后可以有效地解决以下问题:
给定偏移量
k
,从位于(零,n-1
个)模式之后的位流中的该位置开始获得64位。
显然,该模式的重复周期为n
,因此,对于n
的每个给定值,只需生成ulong
个不同的n
。这可以明确地完成,在预处理中构造所有这些(它们可以以任何明显的方式构造,它并不重要,因为它只发生一次),或者通过仅存储而更隐蔽地保留。 n
的每个值的两个 ulongs(这在n < 64
的假设下工作,见下文),然后通过一些移位/ ORing从它们中提取范围。无论哪种方式,使用offset % n
来计算要检索的模式(因为偏移量以可预测的方式增加,不需要实际的模运算 [1] )。
即使使用第一种方法,内存消耗也是合理的,因为此优化只是对低n
的优化:特别是对于n > 64
,每个字平均少于1个零,所以&#34;老式的方式&#34;访问n
的每个倍数并重置该位开始跳过工作,而上述技巧仍会访问每个字,并且不能再一次重置多个位。
[1]:如果同时有多个n
正在进行中,可能的策略是将数组offsets
保留在offsets[n] = offset % n
,其中可能是int next = offsets[n] + _64modn[n]; // 64 % n precomputed
offsets[n] = next - (((n - next - 1) >> 31) & n);
更新根据:(未经测试)
n
每当next >= n
时都会减去n
的想法。只需要进行一次减法,因为偏移量和添加到偏移量的东西已经减去模n
。
这个偏移量增量可以使用System.Numerics.Vectors来完成,与实际硬件相比,它功能很差但是能够做到这一点。它无法进行转换(是的,它很奇怪),但它可以无分支方式实现比较。
每个值n
执行一次传递更容易,但以缓存不友好的方式触及大量内存。同时做很多不同的offset % 3
可能也不是很好。我想你只需要记下那个......
此外,您可以考虑对某些低数字进行硬编码,类似offset % variable
的效果非常高(与template< template <typename...> class Container, typename ... Ts >
void printMap(Container<int, long, Ts...> inputMap,
bool additionalParam = false)
不同)。这确实需要手动循环展开,这有点烦人,但它实际上更简单,只是在代码行方面很大。