【问题标题】:Bit array concatenation in CC中的位数组连接
【发布时间】:2021-09-24 09:44:19
【问题描述】:

我有一个 32 位字数组,需要以不同方式连接它们。

uint32_t data[144];

在一种情况下,我需要将 36 位放在一起并用它做一些有用的事情。为此,我有以下工作代码:

// data is filled with useful bits
int lower_remainder = 0;
int upper_remainder;
uint64_t result[2];
int idx = 144;
for(int i=127; i>=0; i--) {
    upper_remainder = 32-lower_remainder;
    result[i%2] = (((uint64_t)data[idx-1] << upper_remainder) | (data[idx] >> lower_remainder)) & 0xFFFFFFFFF; // Note mask 0xFFFFFFFFF has 9! F's to get 36 bits
    idx--;
    lower_remainder += 4;
    if(lower_remainder == 32) {
        lower_remainder = 0;
        idx--;
    }
    if(i%2 == 0) {
        // Do something with result
    }
}

同样,上面的代码运行良好。

在另一种情况下,我需要将 39 位放在一起。所以我尝试了许多不同的方法来使上面的代码通用,但我在这里失败了。主要是因为我得到:

(data[143] << 32 | data[144] >> 0)  | 0x7FFFFFFFFF; // 0x7FFFFFFFFF mask for 39 bits
(data[142] << 25 | data[143] >> 7)  | 0x7FFFFFFFFF;
(data[141] << 18 | data[142] >> 14) | 0x7FFFFFFFFF;
(data[140] << 11 | data[141] >> 21) | 0x7FFFFFFFFF;

下一个一定是这样的

//     3 bits         32 bits          4bits
(data[138] << 36 | data[139] << 4 | data[140] >> 28) | 0x7FFFFFFFFF;

所以现在必须从 3 个字段中获取数据。我能够为一个案例开发代码,但每次尝试使其通用化都行不通。我还有其他情况,例如需要 72 位(为此我需要 uint64_t 以外的其他东西来存储每个数据......)。

感谢任何帮助/提示/链接。

谢谢, 阿米尔

PS> 我对 data[0] 不感兴趣,因此像上面的代码一样跳过它。

【问题讨论】:

  • 是否准确描述了问题的要点:“一般提取打包到 32 位 uint 数组中的 X 位值?,其中 X 可以是 36、39 或 72”?
  • 如果diag(如data)是uint32_t的数组,那么像diag[143] &lt;&lt; 32diag[138] &lt;&lt; 36这样的表达式可能会失败。您需要对uint64_t 进行初步转换(实际上您在工作代码中已经有了):(uint64_t)diag[143] &lt;&lt; 32 等。
  • 我的意思是写数据而不是诊断,我的错,我把它改成了数据。但是,是的,我正在为 64 岁做演员。
  • 您想一次从数组 36 中获取,或者您想访问数组,就好像它是一个元素数组,每个元素都有 36 位?即你想要give_me_next_n_bits(void *data, unsigned bitcount) 还是你想要access(void *data, size_t elemidx)?你打算写一个比特流式的库吗?你是从 LSB 还是 MSB 开始计算位?

标签: c algorithm bitwise-operators


【解决方案1】:

不确定这是否能完全满足您的需求,但是当我需要这种东西时,我会编写一些简单但非常通用的代码,以“累加器”为中心。我将位从输入移入累加器,然后将它们移出到输出,累加器会自动处理输入和输出字之间的所有奇怪边界。

[免责声明:我很晚才意识到这段代码可能存在一些问题。详情如下。]

基本大纲是这样的:

uint64_t accum = 0;
int nb = 0;     /* number of bits currently present in accum */

int ini = 1;    /* skipping data[0] */
uint64_t out;
int outi;
int nwant = 39;

for(outi = 0; outi < 5; outi++) {
    /* make sure accumulator has enough bits */
    while(nb < nwant) {
        accum = (accum << 32) | data[ini++];
        nb += 32;
    }

    out = (accum >> (nb - nwant)) & MASK(nwant);  /* top 'nwant' bits of accum */
    nb -= nwant;

    printf("%d: %llx %llu\n", outi, out, out);
}

正如@KamilCuk 在评论中提到的,有很多方法可以设置它。在这里,我将data[1]..data[143] 视为一个 4576 位的巨型数组,其中data[1] 的 MSB 是最重要的位,并且该位是前 39 位中的第一个(也是最重要的) -位词我提取。然后,此代码可以再提取 116 个 39 位字,总共 117 个,剩下 13 位。 4576位数组的最低位是data[143]的LSB,data[143]贡献了第117个39位字的低位,剩下的13位:

        +-------+-------+-------+---   ---+-------+-------+
data:   |   1   |   2   |   3   |   ...   |  142  |  143  |
        +-------+-------+-------+---   ---+-------+-------+

        +---------+---------+---------+-   -+---------+
output: |    0    |    1    |    2    | ... |   116   |
        +---------+---------+---------+-   -+---------+

(所有 MSB 在左侧,所有 LSB 在右侧。)

这行得通,这是一种思考方式,但现在我更仔细地研究了您的问题,看起来您可能希望将 data[0] 视为数组中最不重要的词,而不是最重要的词-重大。所以我的这段代码需要一些调整。

一种重新排列是将蓄能器的填充更改为:

    accum |= (uint64_t)data[ini++] << nb;
    nb += 32;

和这样的清空(分配给out):

out = accum & MASK(nwant);
accum >>= nwant;
nb -= nwant;

这会让图片更像这样:

      +-------+-------+---   ---+-------+-------+-------+
data: |  143  |  142  |   ...   |   3   |   2   |   1   |
      +-------+-------+---   ---+-------+-------+-------+

          +---------+-   -+---------+---------+---------+
output:   |   116   | ... |    2    |    1    |    0    |
          +---------+-   -+---------+---------+---------+

现在,免责声明的其余部分:

问题是,如果累加器中的位多于 32 位但少于 39 位,它就会搞砸。 (我不确定在这种情况下是否会发生这种情况,但在一般情况下,它肯定会发生。)这两行

accum = (accum << 32) | data[ini++];

accum |= (uint64_t)data[ini++] << nb;

是可疑的,因为它们可能会在有机会使用累加器之前将数据丢失到累加器的左侧。当然,有一些方法可以解决这个问题,但是代码看起来比较混乱,我现在没有时间编写它。 (对不起。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-05-03
    • 1970-01-01
    • 2016-11-24
    • 2015-11-13
    • 2011-01-14
    • 2014-08-06
    • 1970-01-01
    相关资源
    最近更新 更多