如何将字节数组移动 12 位
我想将字节数组的内容左移 12 位。
例如,从这个 uint8_t shift[10]
类型的数组开始:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xBC}
我想将其向左移动 12 位,结果是:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xC0, 0x00}
I want to shift the contents of an array of bytes by 12-bit to the left.
For example, starting with this array of type uint8_t shift[10]
:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0A, 0xBC}
I'd like to shift it to the left by 12-bits resulting in:
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAB, 0xC0, 0x00}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
让我们让它成为在 8 位整数数组中移动
N
位的最佳方式。我想从这里开始,您必须找到利用这些数据在数组中移动整数的最佳方法。 通用算法是通过从数组右侧开始并移动每个整数
F
索引来应用完整的整数移位。 零填充新空的空间。 然后最后对所有索引执行R
位移位,再次从右侧开始。在将
0xBC
移位R
位的情况下,您可以通过按位 AND 计算溢出,并使用位移运算符进行移位:请记住,4 位是只是一个简单的掩码:0x0F 或只是 0b00001111。 这很容易计算、动态构建,甚至可以使用简单的静态查找表。
我希望这足够通用。 我根本不擅长 C/C++,所以也许有人可以清理我的语法或更具体。
额外奖励:如果您对 C 语言很熟练,您也许能够将多个数组索引编入单个 16、32 甚至 64 位整数并执行移位。 但这可能不太便携,我建议不要这样做。 只是一个可能的优化。
Lets make it the best way to shift
N
bits in the array of 8 bit integers.I guess from here you would have to find the most optimal way to make use of this data to move around ints in an array. Generic algorithms would be to apply the full integer shifts by starting from the right of the array and moving each integer
F
indexes. Zero fill the newly empty spaces. Then finally perform anR
bit shift on all of the indexes, again starting from the right.In the case of shifting
0xBC
byR
bits you can calculate the overflow by doing a bitwise AND, and the shift using the bitshift operator:Keep in mind that the 4 bits is just a simple mask: 0x0F or just 0b00001111. This is easy to calculate, dynamically build, or you can even use a simple static lookup table.
I hope that is generic enough. I'm not good with C/C++ at all so maybe someone can clean up my syntax or be more specific.
Bonus: If you're crafty with your C you might be able to fudge multiple array indexes into a single 16, 32, or even 64 bit integer and perform the shifts. But that is prabably not very portable and I would recommend against this. Just a possible optimization.
这是一个使用临时变量的可行解决方案:
调用此函数 3 次以实现 12 位移位。
由于使用了临时变量,迈克的解决方案可能更快。
Here a working solution, using temporary variables:
Call this function 3 times for a 12-bit shift.
Mike's solution maybe faster, due to the use of temporary variables.
32 位版本...:-) 处理 1 <= count <= num_words
The 32 bit version... :-) Handles 1 <= count <= num_words
求指点万岁!
该代码的工作原理是向前查看每个字节的 12 位并向前复制正确的位。 12 位是下一个字节的下半部分(nybble)和 2 个字节之外的上半部分。
好吧,我想说正常的移位操作就是这样做的(称为溢出),并且只是让多余的位从右侧或左侧掉落。 如果您愿意的话,它很容易携带 - 只需在开始移位之前保存 12 位即可。 也许您想要循环移位,将溢出的位放回底部? 也许您想重新分配数组并使其更大? 将溢出返回给调用者? 如果非零数据溢出,则返回布尔值? 你必须定义进位对你来说意味着什么。
Hurray for pointers!
This code works by looking ahead 12 bits for each byte and copying the proper bits forward. 12 bits is the bottom half (nybble) of the next byte and the top half of 2 bytes away.
Well, I'd say a normal shift operation does just that (called overflow), and just lets the extra bits fall off the right or left. It's simple enough to carry if you wanted to - just save the 12 bits before you start to shift. Maybe you want a circular shift, to put the overflowed bits back at the bottom? Maybe you want to realloc the array and make it larger? Return the overflow to the caller? Return a boolean if non-zero data was overflowed? You'd have to define what carry means to you.
这是我的解决方案,但更重要的是我解决问题的方法。
我通过
这向我展示了这种模式:
iL
为a[i]
的低位 nybble(半字节),iH
为iH
的高位 nybble code>a[i]iH = (i+1)L
iL = (i+2)H
此模式适用于所有字节。
翻译成 C 语言,这意味着:
我们现在又做了三个观察:
a[i+2]
的内容,因此这只影响最后两个字节因此,我们
N-2 个字节
并执行来处理一般情况上面的一般计算iH = (i+1)L
来处理倒数第二个字节,在0
来处理最后一个字节给定
a 的情况下,
长度为N
,我们得到:就是这样……数组左移了
12 位
。 它可以很容易地推广到移位N位
,注意会有M
赋值语句,其中M =位数模8
,我相信。可以在某些机器上提高循环的效率
通过转换为指针并使用 CPU 支持的最大整数数据类型,
。 (我刚刚输入了这个,所以现在是某人检查代码的好时机,特别是因为位调整非常容易出错。)
Here's my solution, but even more importantly my approach to solving the problem.
I approached the problem by
This showed me the pattern:
iL
be the low nybble (half byte) ofa[i]
iH
be the high nybble ofa[i]
iH = (i+1)L
iL = (i+2)H
This pattern holds for all bytes.
Translating into C, this means:
We now make three more observations:
12 bits
at the end will be zero.a[i+2]
, this only affects the last two bytesSo, we
N-2 bytes
and performing the general calculation aboveiH = (i+1)L
0
given
a
with lengthN
, we get:And there you have it... the array is shifted left by
12 bits
. It could easily be generalized to shiftingN bits
, noting that there will beM
assignment statements whereM = number of bits modulo 8
, I believe.The loop could be made more efficient on some machines by translating to pointers
and by using the largest integer data type supported by the CPU.
(I've just typed this in, so now would be a good time for somebody to review the code, especially since bit twiddling is notoriously easy to get wrong.)
有一些边缘情况使这成为一个巧妙的问题:
这是一个循环的简单解决方案在数组上,将下一个字节的低位半字节复制到其高位半字节中,并将下一个(+2)字节的高位半字节复制到其低位半字节中。 为了避免取消引用前瞻指针两次,它维护一个包含“最后”和“下一个”字节的双元素缓冲区:
考虑边界情况,这会连续激活函数的更多部分:
length
为零,我们在不触及内存的情况下退出。length
为 1 时,我们将唯一的元素设置为零。length
为2时,我们将第一个字节的高位半字节设置为第二个字节的低位半字节(即位12-16),并将第二个字节设置为零。 我们不激活循环。length
大于 2 时,我们会进入循环,在两元素缓冲区中重新排列字节。如果效率是您的目标,那么答案可能很大程度上取决于您的机器的架构。 通常,您应该维护两元素缓冲区,但一次处理一个机器字(32/64 位无符号整数)。 如果您要移动大量数据,则值得将前几个字节视为特殊情况,以便您可以使机器字指针字对齐。 如果访问落在机器字边界上,大多数 CPU 会更有效地访问内存。 当然,尾随字节也必须进行特殊处理,这样您就不会触及数组末尾之后的内存。
There are a couple of edge-cases which make this a neat problem:
Here's a simple solution which loops over the array copying the low-order nibble of the next byte into its high-order nibble, and the high-order nibble of the next-next (+2) byte into its low-order nibble. To save dereferencing the look-ahead pointer twice, it maintains a two-element buffer with the "last" and "next" bytes:
Consider the boundary cases, which activate successively more parts of the function:
length
is zero, we bail out without touching memory.length
is one, we set the one and only element to zero.length
is two, we set the high-order nibble of the first byte to low-order nibble of the second byte (that is, bits 12-16), and the second byte to zero. We don't activate the loop.length
is greater than two we hit the loop, shuffling the bytes across the two-element buffer.If efficiency is your goal, the answer probably depends largely on your machine's architecture. Typically you should maintain the two-element buffer, but handle a machine word (32/64 bit unsigned integer) at a time. If you're shifting a lot of data it will be worthwhile treating the first few bytes as a special case so that you can get your machine word pointers word-aligned. Most CPUs access memory more efficiently if the accesses fall on machine word boundaries. Of course, the trailing bytes have to be handled specially too so you don't touch memory past the end of the array.
@Joseph,请注意变量是 8 位宽,而移位是 12 位宽。 您的解决方案仅适用于 N <= 可变大小。
如果您可以假设您的数组是 4 的倍数,您可以将数组转换为 uint64_t 数组,然后对其进行处理。 如果它不是 4 的倍数,您可以尽可能多地处理 64 位块,然后逐一处理剩余部分。
这可能需要更多的编码,但我认为最终会更优雅。
@Joseph, notice that the variables are 8 bits wide, while the shift is 12 bits wide. Your solution works only for N <= variable size.
If you can assume your array is a multiple of 4 you can cast the array into an array of uint64_t and then work on that. If it isn't a multiple of 4, you can work in 64-bit chunks on as much as you can and work on the remainder one by one.
This may be a bit more coding, but I think it's more elegant in the end.