首先,要说你的样本数是错误的,因为第二个的最高位是一个,它应该大于2147483643,但它只是4194303,第三个应该是7,所以我猜你在将它们转换为十进制时已经反转了位位置。请参阅我在main() 开头的最后一个完整代码的评论,关于如何确定数字(在您的示例中看起来)与您的位模式对应的数字是(十六进制/十进制):
[0xffffffff/4294967295][0xfffffc00/4294966272][0x00000007/7]
(如果我们把更多的权重数字放在左边,为什么我们不也用二进制呢?)
为了解决你的问题,你可以考虑当你有n连续的一个数字的LSB部分,你增加一个值,那么你有所有这些连续的切换到零(通过进位传播),直到您拥有的最后一个,并且如果您有n 连续零并递减该值,那么您将所有这些零转换为一......好吧,有一个更多位,因为进位再次进一步级联。这个想法是检查我们在 LSB 中有什么位,并根据这一点,递增或递减该值并将其与原始值进行异或……您将得到的结果是一个在LSB 与 LSB 相等的位加一,例如:
1100100011111111
由于 LSB 为 1,我们将其递增:
1100100100000000
^^^^^^^^^ changed bits.
如果我们现在将这个值与之前的值进行异或:
0000000111111111 => 9 "1" bits, that indicate that 8 "1" consecutive bits were present
如果我们准备一个switch 语句,其中包含我们可以从该函数中获得的所有可能值,您可以获得以下结果的非常有效的方法:
int get_consecutive_bits(unsigned value)
{
unsigned next = value;
switch (value) {
case 0: case ~0: return 32; /* these are special cases, see below */
}
switch (value & 1) { /* get the lower bit */
case 0: next--; break; /* decrement */
case 1: next++; break; /* increment */
}
switch (value ^ next) { /* make the xor */
case 0x00000003: return 1;
case 0x00000007: return 2;
case 0x0000000f: return 3;
case 0x0000001f: return 4;
case 0x0000003f: return 5;
case 0x0000007f: return 6;
/* ... */
case 0xffffffff: return 31;
} /* switch */
}
现在您必须累积该值,以防下一个数组单元以与您完成前一个相同的位值开始。我们从来没有0x00000001 的case 语句的原因是我们在第二位强制进位,所以我们总是有一个1 或更大的值,两个位改变(...0000001 => ...0000010 => ...0000011 和@987654337 @) 这也意味着对于值0000...0000 和1111...1111,我们应该得到比字长多一点的值,使这些值变得特殊(因为它们使进位转到 msb 的下一位,第 33 位)所以我们首先检查这些值。
这是在一个数组单元的块中完成任务的一种非常有效的方法。当你得到的值包括 MSB 时,你必须累积,因为下一个单词可以从你之前结束的那个位开始。
下面的代码应该说明算法:
pru_49297910.c
/* pru_49297910.c -- answer to https://stackoverflow.com/questions/49297910/
* Author: Luis Colorado <luiscoloradourcola@gmail.com>
* Date: Wed Apr 24 11:12:21 EEST 2019
* Copyright: (C) Luis Colorado. All rights reserved.
* License: BSD. Open source.
*/
#include <cassert>
#include <iostream>
#define BITS_PER_ELEMENT 32
int get_consecutive_bits(unsigned value)
{
switch (value) {
case 0: case ~0: /* these are special cases, see below */
return BITS_PER_ELEMENT;
}
unsigned next = value;
switch (value & 1) { /* get the lower bit */
case 0: next--; break; /* decrement */
case 1: next++; break; /* increment */
}
switch (value ^ next) { /* make the xor */
case 0x00000003: return 1; case 0x00000007: return 2;
case 0x0000000f: return 3; case 0x0000001f: return 4;
case 0x0000003f: return 5; case 0x0000007f: return 6;
case 0x000000ff: return 7; case 0x000001ff: return 8;
case 0x000003ff: return 9; case 0x000007ff: return 10;
case 0x00000fff: return 11; case 0x00001fff: return 12;
case 0x00003fff: return 13; case 0x00007fff: return 14;
case 0x0000ffff: return 15; case 0x0001ffff: return 16;
case 0x0003ffff: return 17; case 0x0007ffff: return 18;
case 0x000fffff: return 19; case 0x001fffff: return 20;
case 0x003fffff: return 21; case 0x007fffff: return 22;
case 0x00ffffff: return 23; case 0x01ffffff: return 24;
case 0x03ffffff: return 25; case 0x07ffffff: return 26;
case 0x0fffffff: return 27; case 0x1fffffff: return 28;
case 0x3fffffff: return 29; case 0x7fffffff: return 30;
case 0xffffffff: return 31;
} /* switch */
assert(!"Impossible");
return 0;
}
#define FLUSH() do{ \
runlen(accum, state); \
state ^= 1; \
accum = 0; \
} while (0)
void run_runlen_encoding(unsigned array[], int n, void (*runlen)(int, unsigned))
{
int state = 0; /* always begin in 0 */
int accum = 0; /* accumulated bits */
while (n--) {
/* see if we have to change */
if (state ^ (array[n] & 1)) /* we changed state */
FLUSH();
int nb = BITS_PER_ELEMENT; /* number of bits to check */
int w = array[n];
while (nb > 0) {
int b = get_consecutive_bits(w);
if (b < nb) {
accum += b;
FLUSH();
w >>= b;
nb -= b;
} else { /* b >= nb, we only accumulate nb */
accum += nb;
nb = 0;
}
}
}
if (accum)
FLUSH();
} /* run_runlen_encoding */
void output_runlen(int n, unsigned kind)
{
if (n) { /* don't print for n == 0 */
static int i = 0;
std::cout << "[" << n << "/" << kind << "]";
if (!(++i % 10))
std::cout << std::endl;
}
} /* output_runlen */
int main()
{
/* 0b1111_1111_1111_1111_1111_1111_1111_1111, 0b1111_1111_1111_1111_1111_1100_0000_0000, 0b0000_0000_0000_0000_0000_0000_0000_0111 */
/* 0xf____f____f____f____f____f____f____f, 0xf____f____f____f____f____c____0____0, 0x0____0____0____0____0____0____0____7 */
/* 0xffffffff, 0xfffffc00, 0x00000007 */
unsigned int array[] =
#if 1
{ 0xffffffff, 0xfffffc00, 0x00000007 }; /* correct values for your example */
#else
{ 4294967295, 4194303, 3758096384 }; /* original values, only first matches. */
#endif
size_t array_n = sizeof array / sizeof array[0];
run_runlen_encoding(array, array_n, output_runlen);
std::cout << std::endl;
} /* main */
注意:
由于我们需要计算进位位在一个增量中跳跃的距离,我们必须从低位到最高位,使输出的顺序与您尝试的相反,但我相信您会能够更改顺序以使其显示为您在问题中所述。
程序输出显示:
$ pru_49297910
[3/1][39/0][54/1]