根据位掩码拆分多个字节

Posted

技术标签:

【中文标题】根据位掩码拆分多个字节【英文标题】:Split multiple bytes according to bit masks 【发布时间】:2022-01-18 12:16:46 【问题描述】:

我正在尝试根据位掩码拆分字节。

考虑这两个字节(二进制中的 1000 为 short int):

11101000

00000011

还有这三个面具:

00000011

11111111

00111111

我要做的是根据提供的掩码将两个原始字节分成三个字节。

结果应该是:

00000000 第一个字节

11111010为第二个(原来的字节1和2因为掩码合并了)

00000000 为第三个(剩余位用零填充)

在 Java 或 C 中最简单的方法是什么?

【问题讨论】:

您需要了解按位运算符(&|)。但目前还不清楚哪个字节应该用什么来掩盖。 我知道如何使用位运算符。由于掩码,我试图以最简单的方式将第一个字节的一部分与第二个字节的一部分以正确的顺序合并。我知道这是一个简单的例子,但无论提供什么掩码,它都必须工作,所以我需要一些位移来调整正确的顺序。 掩码是什么意思? 您是在寻找通用解决方案,还是仅当掩码具有连续的解决方案时,或者最终只是连续的解决方案?您应该使用和/或/xor/shifts,还是可以使用popcountpdep 之类的操作? @corir146 你需要给我们看一些例子。 【参考方案1】:

在 C 中,如果使用 x86,则这是单个 pdep 操作。

#include <immintrin.h>

int msk(int num) 
    int src =  0b0000001111101000;
    int mask = 0b001111111111111100000011;

    int result = _pdep_u32(src,mask);

    int expected_result = 0b000000001111101000000000;

    if (result == expected_result) 
        return 1; // returns this
     else 
        return 0;
    

见_pdep_u32 in Intel Intrinsic Guide。

https://godbolt.org/z/b6E6M8518


如果您的输入/输出是正好 4 个字节的数组,您可以将 memcpy 从数组到 int 并返回。

如果您不仅针对 x86,还针对没有 BMI2 的旧 x86,或者想要 Java 解决方案,则必须从 PDEP 文档中实现此算法:

tmp := a
dst := 0
m := 0
k := 0
DO WHILE m < 32
    IF mask[m] == 1
        dst[m] := tmp[k]
        k := k + 1
    FI
    m := m + 1
OD

dst[m]tmp[k] 可以通过数组索引和位移来完成,具体来说dst[m] := tmp[k] 是(假设为8 位字节):

unsigned char bit = (dst[k/8] >> (k%8)) & 1;
dst[m/8] |= bit << (m%8)

请注意,直接实现不仅有点复杂,而且效率也较低,因为pdep 是单 CPU 指令。但是我不确定Java是否暴露了它,如果没有,那么使用JNI调用C实现是否值得。

【讨论】:

没错,这就是我的意思。你知道Java中有没有等价的函数?我需要用 C 和 Java 编写这个函数。我的输入是字节数组(4 个字节的数组而不是 int),你知道是否有适用于数组的东西吗? @corir146,在C 中,您可以将memcpy 数组内容转为int,然后将memcpy 生成的int 转为数组。对于 Java,可能没有简单的方法,您必须使用带有两个计数器的循环和一位复制来实现该算法。我已经编辑了我的答案 谢谢!我将实现这个算法,以便可以在 C 和 Java 中使用字节数组。

以上是关于根据位掩码拆分多个字节的主要内容,如果未能解决你的问题,请参考以下文章

将 __m256i 寄存器转换为 uint64_t 位掩码,以便每个字节值处的值是输出中的设置位

如何从 __m64 值的 lsb 创建一个 8 位掩码?

linux网络基础---子网掩码和子网划分

Swift 2/Xcode 7 beta - 多个位掩码产生错误

无法应用位掩码

如何根据字节大小拆分熊猫数据帧