一些初步注意事项:
- 您的示例数据只有63个值。出于下面我的代码示例的目的,我将
35
的缺失值随意添加到列表的末尾。
- 在您的问题中,没有任何关于您如何首先陷入这种混乱状态的细节。不用说,但是无论如何我都会提到: best 解决方案是完全消除问题的解决方案。在您的确切情况下是否有可能这样做,不要紧怎么做,我不能说,因为问题中缺少细节。
所有所说的…
我的另一个想法是:
ulong unsorted = x;
ulong sorted = 0;
sorted += (unsorted & 0x0001000010000000) >> 18 //bits that are shifted the same manner
//go on
该想法可能会奏效。但是您没有在问题中提供足够的详细信息让其他人知道,因为我们没有有关为何对位进行重新排序的任何信息。您似乎在想编写特殊情况的代码,以利用首先导致位排序的任何模式,但是由于没有关于该模式的具体细节,没有其他人可以充实这种想法。
我的一个想法是将ulong分为四个短裤,将它们放入一个可查询的表中,每个返回一个排序后的短裤。但是,由于不仅需要在这四个块之间移动许多位,所以仅此一项是行不通的。
这个想法也行得通。没错,您无法映射到short
值(甚至是ushort
)。但是您可以映射到ulong
值,然后合并结果。
当然,对于任何代码来说,第一件事也是最重要的事情就是让它起作用。因此,恕我直言,从一个可以验证的更简单的实现入手是有意义的。完成之后,您就可以继续进行其他选择了。
这里是一种选择:
static readonly int[] bitOrder = // NOTE: 35 not in original example,added here at end arbitrarily
{ // so that a valid implementation can be demonstrated
31,39,34,27,43,30,38,26,42,33,29,37,23,47,25,41,22,46,32,28,36,21,45,24,40,20,44,48,16,49,17,50,18,51,19,12,52,8,56,13,53,4,60,14,54,9,57,15,55,5,61,1,10,58,6,62,11,59,2,7,63,3,35
};
private static ulong[] BuildBitwiseMapping()
{
ulong[] bitwiseMapping = new ulong[bitOrder.Length];
for (int i = 0; i < bitwiseMapping.Length; i++)
{
bitwiseMapping[i] = 1UL << bitOrder[i];
}
return bitwiseMapping;
}
private static ulong SortBits(ulong[] bitwiseMapping,ulong value)
{
ulong sorted = 0,mask = 1;
for (int i = 0; i < bitwiseMapping.Length; i++,mask <<= 1)
{
if ((value & bitwiseMapping[i]) != 0)
{
sorted |= mask;
}
}
return sorted;
}
您将首先调用BuildBitwiseMapping()
,然后对每次调用SortBits()
使用返回的数组。自然地,您可以将内置数组作为static readonly
字段并入,以简化对SortBits()
的调用。
这必须为每个位循环一次,这不一定是最有效的。但是除了循环条件之外,严格来说,它仅是查找和按位“或”运算,因此已经相当快了。
如果您想使用查找表的思想来改进它,那就很简单:
private static ulong[][] BuildWordwiseMapping(ulong[] bitwiseMapping)
{
ulong[][] result = new ulong[4][];
ulong increment = 1;
for (int i = 0; i < result.Length; i++)
{
result[i] = new ulong[ushort.MaxValue + 1];
ulong value = 0;
for (int j = 0; j <= ushort.MaxValue; j++)
{
result[i][j] = SortBits(bitwiseMapping,value);
value += increment;
}
increment = value;
}
return result;
}
private static ulong SortBits(ulong[][] wordwiseMapping,ulong value)
{
ulong sorted = 0;
for (int i = 0; i < wordwiseMapping.Length; i++,value >>= 16)
{
int ushortPart = (int)(value & 0xffff);
sorted |= wordwiseMapping[i][ushortPart];
}
return sorted;
}
上面的代码从第一个示例中的64位按位表开始,并使用它来构建四个更大的表以用于按字查找。
您需要四个不同的表,一个用于原始ulong
值的每个位子集,一个表,因为它们的映射当然不同。它们可以分布在整个ulong
结果中,因此表元素大小仍然需要为ulong
。
这将为您提供四个表,每个表包含65536个元素,每个元素为8个字节长,总内存占用为2MB。另一方面,虽然较简单的按位版本每个值需要64次循环迭代,而按字版本仅需要4次循环。这可以显着提高吞吐量。否则可能总体上影响不大;它实际上取决于该代码实际上到底有多大的瓶颈,以及四表版本的速度有多快。
您可能在上面已经注意到,从技术上讲,实际上不需要在每个表中处理值0
,因为不会为这些值设置任何位,无论它们出现在什么位置在原始的ulong
中。但是,实际上可能是对0
进行 compare 并处理这种特殊情况,然后只查找NOP“零映射到零”值,这会在性能上花费更多。
,
执行此排列的另一种方法是:
ulong permute(ulong x)
{
x = bit_permute_step(x,0x00000000c539d22d,32);
x = bit_permute_step(x,0x0000cbc10000749e,16);
x = bit_permute_step(x,0x0039007e00a9007f,8);
x = bit_permute_step(x,0x06010e04070e0507,4);
x = bit_permute_step(x,0x2113320311022110,2);
x = bit_permute_step(x,0x5401151151100141,1);
x = bit_permute_step(x,0x0032323110011333,0x030b0a0b080e0d00,0x00a5009500220097,0x00005cd6000043cc,0x00000000b3f003f3,32);
return x;
}
bit_permute_step
的定义为:
ulong bit_permute_step(ulong source,ulong mask,int shift)
{
ulong t = ((source >> shift) ^ source) & mask;
return (source ^ t) ^ (t << shift);
}
该构造是一个完整的11步Beneš网络(6 * 2-1,其中6是64的以2为底的对数)。这是一种非常通用的技术,可以处理任何排列,在许多情况下,有些特殊情况下的技术会更好,但我找不到这种方法。