如何将32个字符(0/1)的序列转换为32位(uint32_t)? [英] How to convert a sequence of 32 char (0/1) to 32 bits (uint32_t)?

查看:189
本文介绍了如何将32个字符(0/1)的序列转换为32位(uint32_t)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个从文件中读取的char数组(通常长数千个字节),全部由0和1(不是'0'和'1'组成,在这种情况下,我可以使用strtoul).我想将它们打包成单个位,从而将每个32个字符转换成单个uint32_t.我应该用32个部分编写一个移位运算,还是有一个更明智的方法?

I have an array of char (usually thousands of bytes long) read from a file, all composed of 0 and 1 (not '0' and '1', in which case I could use strtoul). I want to pack these into single bits, thus converting each 32 char into a single uint32_t. Should I write a bit shift operation with 32 parts, or is there a saner way?

out[i/32] = 
    data[i] << 31 |
    data[i+1] << 30 |
    data[i+2] << 29 |
    data[i+3] << 28 |
    data[i+4] << 27 |
    data[i+5] << 26 |
    data[i+6] << 25 |
    data[i+7] << 24 |
    data[i+8] << 23 |
    data[i+9] << 22 |
    data[i+10] << 21 |
    data[i+11] << 20 |
    data[i+12] << 19 |
    data[i+13] << 18 |
    data[i+14] << 17 |
    data[i+15] << 16 |
    data[i+16] << 15 |
    data[i+17] << 14 |
    data[i+18] << 13 |
    data[i+19] << 12 |
    data[i+20] << 11 |
    data[i+21] << 10 |
    data[i+22] << 9 |
    data[i+23] << 8 |
    data[i+24] << 7 |
    data[i+25] << 6 |
    data[i+26] << 5 |
    data[i+27] << 4 |
    data[i+28] << 3 |
    data[i+29] << 2 |
    data[i+30] << 1 |
    data[i+31];

如果这种怪异的移位是运行时最快的,那么我就必须坚持下去.

If this monstrous bit shift is the fastest in run time, then I'll have to stick to it.

推荐答案

如果您不需要输出位以与输入字节完全相同的顺序出现,但是可以将它们以特定的方式交织"因此,一种快速而又可移植的方法是采用8个8字节的块(总共64个字节),并将所有LSB合并为一个8字节的值.

If you don't need the output bits to appear in exactly the same order as the input bytes, but if they can instead be "interleaved" in a specific way, then a fast and portable way to accomplish this is to take 8 blocks of 8 bytes (64 bytes total) and to combine all the LSBs together into a single 8 byte value.

类似的东西:

uint32_t extract_lsbs2(uint8_t (&input)[32]) {
  uint32_t t0, t1, t2, t3, t4, t5, t6, t7;
  memcpy(&t0, input + 0 * 4, 4);
  memcpy(&t1, input + 1 * 4, 4);
  memcpy(&t2, input + 2 * 4, 4);
  memcpy(&t3, input + 3 * 4, 4);
  memcpy(&t4, input + 4 * 4, 4);
  memcpy(&t5, input + 5 * 4, 4);
  memcpy(&t6, input + 6 * 4, 4);
  memcpy(&t7, input + 7 * 4, 4);

  return 
    (t0 << 0) |
    (t1 << 1) |
    (t2 << 2) |
    (t3 << 3) |
    (t4 << 4) |
    (t5 << 5) |
    (t6 << 6) |
    (t7 << 7);
}

这会在大多数编译器上生成不可怕,不完美"的代码.

This generates "not terrible, not great" code on most compilers.

如果使用uint64_t而不是uint32_t,则在64位平台上,通常速度要快两倍(假设要转换的总字节数超过32个).

If you use uint64_t instead of uint32_t it would generally be twice as fast (assuming you have more than 32 total bytes to transform) on a 64-bit platform.

使用SIMD,您可以像两个指令(对于AVX2,但可以使用任何x86 SIMD ISA一样)轻松地将整个操作向量化:比较和pmovmskb.

With SIMD you could easy vectorize the entire operation in something like two instructions (for AVX2, but any x86 SIMD ISA will work): compare and pmovmskb.

这篇关于如何将32个字符(0/1)的序列转换为32位(uint32_t)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆