好吧,我有以下问题:我有一组8个(无符号)数字都是17位(a.k.a.它们都不比131071大)。由于17位数字是恼人的工作(将它们保存在32位int中是浪费空间),我想将它们变成17个8位数字,如下所示:
如果我有这8个17位整数:
[25409, 23885, 24721, 23159, 25409, 23885, 24721, 23159]
我会把它们变成基础2表示法
["00110001101000001", "00101110101001101", "00110000010010001", "00101101001110111", "00110001101000001", "00101110101001101", "00110000010010001", "00101101001110111"]
然后将其加入一个大字符串:
"0011000110100000100101110101001101001100000100100010010110100111011100110001101000001001011101010011010011000001001000100101101001110111"
然后将其分成17个字符串,每个字符串有8个字符:
["00110001", "10100000", "10010111", "01010011", "01001100", "00010010", "00100101", "10100111", "01110011", "00011010", "00001001", "01110101", "00110100", "11000001", "00100010", "01011010", "01110111"]
最后,将二进制表示转换回整数
[49, 160, 151, 83, 76, 18, 37, 167, 115, 26, 9, 117, 52, 193, 34, 90, 119]
这种方法有效,但效率不高,我正在寻找比这更有效的东西,最好用C ++编码,因为那是我正在使用的语言。我只是想不出任何方法来提高效率,并且17位数字并不是很容易使用(16位数字可以更好地使用)。
提前致谢,xfbs
答案 0 :(得分:10)
按原样存储每个数字的最低16位(即以两个字节为单位)。这留下了每个数字的最重要位。由于有8个这样的数字,只需将8位组合成一个额外的字节。
这将需要与您的方法完全相同的内存量,但将涉及更少的位琐事。
P.S。无论存储方法如何,您都应该使用位操作运算符(<<
,>>
,&
,|
等来完成这项工作;不应该涉及任何基于字符串的中间表示。
答案 1 :(得分:4)
看看std::bitset<N>
。也许你可以把它们塞进那个?
答案 2 :(得分:2)
高效?然后不要使用字符串转换,位域等。管理要做自己的转变以实现这一点。 (注意,数组必须是unsigned
,以便我们在转移时不会遇到问题。
uint32 A[8]; //Your input, unsigned int
ubyte B[17]; //Output, unsigned byte
B[0] = (ubyte)A[0];
B[1] = (ubyte)(A[0] >> 8);
B[2] = (ubyte)A[1];
B[3] = (ubyte)(A[1] >> 8);
.
:
对于最后一个,我们做的是ajx所说的。我们取每个数字的最高位(将它们向右移16位,留下第17位)并通过将每个最高有效位从0移到左边来填充输出的位:
B[16] = (A[0] >> 16) | ((A[1] >> 16) << 1) | ((A[2] >> 16) << 2) | ((A[3] >> 16) << 3) | ... | ((A[7] >> 16) << 7);
嗯,“效率”就是这个。其他更简单的方法也存在。
答案 3 :(得分:1)
虽然你说它们是17位数字,但它们必须存储在32位整数数组中,其中只使用不太重要的17位。您可以从第一个直接提取两个字节(dst[0] = src[0] >> 9
是第一个,dst[1] = (src[0] >> 1) & 0xff
第二个);然后你将第一位“推”为第二位的第18位,这样
dst[2] = (src[0] & 1) << 7 | src[1] >> 10;
dst[3] = (src[1] >> 2) & 0xff;
如果你概括它,你会发现可以应用这个“公式”
dst[2*i] = src[i] >> (9+i) | (src[i-1] & BITS(i)) << (8-i);
dst[2*i + 1] = (src[i] >> (i+1)) & 0xff;
和最后一个:dst[16] = src[7] & 0xff;
。
整个代码看起来像
dst[0] = src[0] >> 9;
dst[1] = (src[0] >> 1) & 0xff;
for(i = 1; i < 8; i++)
{
dst[2*i] = src[i] >> (9+i) | (src[i-1] & BITS(i)) << (8-i);
dst[2*i + 1] = (src[i] >> (i+1)) & 0xff;
}
dst[16] = src[7] & 0xff;
可能更好地分析循环,可以进行优化,这样我们就不需要以特殊的方式处理边界上的情况。 BITS宏创建N位的掩码,设置为1(最低有效位)。类似的东西(要检查更好的方式,如果有的话)
#define BITS(I) (~((~0)<<(I)))
添加强>
这里我认为src是例如int32_t
和dst int8_t
或类似。
答案 4 :(得分:0)
这是在C中,因此您可以改为使用vector
。
#define srcLength 8
#define destLength 17
int src[srcLength] = { 25409, 23885, 24721, 23159, 25409, 23885, 24721, 23159 };
unsigned char dest[destLength] = { 0 };
int srcElement = 0;
int bits = 0;
int i = 0;
int j = 0;
do {
while( bits >= srcLength ) {
dest[i++] = srcElement >> (bits - srcLength);
srcElement = srcElement & ((1 << bits) - 1);
bits -= srcLength;
}
if( j < srcLength ) {
srcElement <<= destLength;
bits += destLength;
srcElement |= src[j++];
}
} while (bits > 0);
免责声明:如果您确实拥有 17个整数(而不是17个不是100000个组),只要您的程序没有慢慢运行,就应该忘记这些优化。
答案 5 :(得分:0)
我可能会这样做。当我正在进行处理时,我不想处理奇怪的类型。由于遗留问题,我可能需要将它们存储在一些时髦的格式中。硬编码的值应该基于17值,只是没有打扰。
struct int_block {
static const uint32 w = 17;
static const uint32 m = 131071;
int_block() : data(151, 0) {} // w * 8 + (sizeof(uint32) - w)
uint32 get(size_t i) const {
uint32 retval = *reinterpret_cast<const uint32 *>( &data[i*w] );
retval &= m;
return retval;
}
void set(size_t i, uint32 val) {
uint32 prev = *reinterpret_cast<const uint32 *>( &data[i*w] );
prev &= ~m;
val |= prev;
*reinterpret_cast<uint32 *>( &data[i*w] ) = val;
}
std::vector<char> data;
};
TEST(int_block_test) {
int_block ib;
for (uint32 i = 0; i < 8; i++)
ib.set(i, i+25);
for (uint32 i = 0; i < 8; i++)
CHECK_EQUAL(i+25, ib.get(i));
}
你可以通过赋予它不好的价值来打破这个,但我会把它作为读者的练习。 :))
老实说,我认为你将它们表示为32位整数并只编写转换函数会更快乐。但我怀疑你无法控制它。