如何有效地将8个17位整数转换为17个8位整数

时间:2011-07-25 17:05:15

标签: c++ integer

好吧,我有以下问题:我有一组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

6 个答案:

答案 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位整数并只编写转换函数会更快乐。但我怀疑你无法控制它。