将位图旋转 90 度
我有一个一个 64 位整数,我需要在 8 x 8 区域中将其旋转 90 度(最好使用直接位操作)。我无法找出任何方便的算法。例如,这样:
// 0xD000000000000000 = 1101000000000000000000000000000000000000000000000000000000000000
1 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
旋转后变成这样:
// 0x101000100000000 = 0000000100000001000000000000000100000000000000000000000000000000
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
我想知道是否有任何解决方案不需要使用任何预先计算的哈希表?
I have a one 64-bit integer, which I need to rotate 90 degrees in 8 x 8 area (preferably with straight bit-manipulation). I cannot figure out any handy algorithm for that. For instance, this:
// 0xD000000000000000 = 1101000000000000000000000000000000000000000000000000000000000000
1 1 0 1 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
after rotation becomes this:
// 0x101000100000000 = 0000000100000001000000000000000100000000000000000000000000000000
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0
I wonder if there's any solutions without need to use any pre-calculated hash-table(s)?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(9)
在不使用任何查找表的情况下,我看不出比单独处理每个位更好的了:
Without using any look-up tables, I can't see much better than treating each bit individually:
有一种有效的方法来执行位反转,即使用 O(log n) 移位操作。如果将 64 位 UINT 解释为 8x8 位数组,则位反转对应于旋转 180 度。
这些转变中有一半有效地执行水平反射;另一半执行垂直反射。为了获得 90 度和 270 度的旋转,可以将正交(即垂直或水平)反射与对角反射结合起来,但后者仍然有点尴尬。
在上面的代码中,reflect_diag()函数仍然需要很多次转换。我怀疑可以用更少的班次来实现这个功能,但我还没有找到一种方法来做到这一点。
There is an efficient way to perform bit reversal, using O(log n) shift operations. If you interpret a 64-bit UINT as an 8x8 array of bits, then bit reversal corresponds to a rotation by 180 degrees.
Half of these shifts effectively perform a horizontal reflection; the other half perform a vertical reflection. To obtain rotations by 90 and 270 degrees, an orthogonal (i.e. vertical or horizontal) reflection could be combined with a diagonal reflection, but the latter remains an awkward bit.
In the above code, the reflect_diag() function still requires many shifts. I suspect that it is possible to implement this function with fewer shifts, but I have not yet found a way to do that.
如果你想快速做到这一点,你不应该反对查找表。
我会将 64 位整数分解为 N 位块,并在位置选择的转置值表中查找 N 位块。如果选择N=1,则需要在两个槽的表中查找64次,速度相对较慢。如果您选择 N=64,则需要一张表和一次查找,但表很大:-}
N=8 似乎是一个很好的折衷方案。您需要 8 个包含 256 个条目的表。代码应如下所示:
每个表都包含预先计算的值,这些值将输入中的连续位“分散”到 64 位转置结果中。理想情况下,您可以离线计算该值并
只需初始化表条目即可。
如果你不关心速度,那么标准数组转置
算法会起作用;只需索引 64 位,就好像它是位数组一样。
我有一种偷偷的怀疑,人们可能能够使用以下方法来计算转置
有点摆弄类型的黑客。
If you're going to do this fast, you shouldn't object to lookup tables.
I'd break the 64 bit integers into N-bit chunks, and look up the N bit chunks in a position-selected table of transpose values. If you choose N=1, you need 64 lookups in tables of two slots, which is relatively slow. If you choose N=64, you need one table and one lookup but the table is huge :-}
N=8 seems like a good compromise. You'd need 8 tables of 256 entries. The code should look something like this:
Each table contains precomputed values that "spread" the contiguous bits in the input across the 64 bit transposed result. Ideally you'd compute this value offline and
simply initialize the table entries.
If you don't care about speed, then the standard array transpose
algorithms will work; just index the 64 bit as if it were a bit array.
I have a sneaking suspicion that one might be able to compute the transposition using
bit twiddling type hacks.
为了扩展我对 Ira 答案的评论,您可以使用:
当然,这取决于 'unsigned long' 是 64 位,并且旋转假设
这些位按行优先顺序排列,最高有效位位于右上角,这似乎是这个问题的情况......
To expand on my comment to Ira's answer, you can use:
This depends on 'unsigned long' being 64 bits, of course, and does the rotate assuming
the bits are in row-major order with the msb being the upper right, which seems to be the case in this question....
使用 IA32 SIMD 这非常容易,有一个方便的操作码可以从 64 位值中提取每八位(这是使用 DevStudio 2005 编写的):
它将数据旋转三次(-270 度),因为 +90 有点棘手(需要多思考一下)
This is quite easy using IA32 SIMD, there's a handy opcode to extract every eighth bit from a 64 bit value (this was written using DevStudio 2005):
It rotates the data three times (-270 degrees) since +90 is a bit trickier (needs a bit more thought)
如果你把它看作一个二维数组,那么你有解决方案吗?
只需将行设为新列即可。
第一行是最后一列,第二行是最后一列,依此类推。
至少在视觉上,它看起来像您的解决方案。
If you look at this as a 2 dimensional array then you have the solution no?
Just make the rows the new columns.
First row is the last column, 2nd is the one before last and so on.
Visually at least, it looks like your solution.
可能是这样的
probably something like that
如果 if-powered 循环是可以接受的,那么位的公式就足够简单了:
Column 和 Row 都是 0 索引的。
这给你这个映射:
If an if-powered loop is acceptable, the formula for bits is simple enough:
Column and Row are 0-indexed.
This gives you this mapping: