max*_*yne 29 java packing bitwise-operators bit-packing
低级别位操作从来都不是我的强项.我将理解一些有助于理解按位运算符的以下用例.考虑...
int age, gender, height, packed_info;
. . . // Assign values
// Pack as AAAAAAA G HHHHHHH using shifts and "or"
packed_info = (age << 8) | (gender << 7) | height;
// Unpack with shifts and masking using "and"
height = packed_info & 0x7F; // This constant is binary ...01111111
gender = (packed_info >> 7) & 1;
age = (packed_info >> 8);
Run Code Online (Sandbox Code Playgroud)
我不确定这段代码是什么以及如何完成的?为什么使用幻数0x7F?如何完成包装和拆包?
tho*_*att 63
正如评论所说,我们将把年龄,性别和身高打包成15位格式:
AAAAAAAGHHHHHHH
Run Code Online (Sandbox Code Playgroud)
让我们从这部分开始:
(age << 8)
Run Code Online (Sandbox Code Playgroud)
首先,年龄有这种格式:
age = 00000000AAAAAAA
Run Code Online (Sandbox Code Playgroud)
其中每个A可以是0或1.
<< 8将位移动到左侧8位,并用零填充间隙.所以你得到:
(age << 8) = AAAAAAA00000000
Run Code Online (Sandbox Code Playgroud)
同理:
gender = 00000000000000G
(gender << 7) = 0000000G0000000
height = 00000000HHHHHHH
Run Code Online (Sandbox Code Playgroud)
现在我们想将这些组合成一个变量.该|运营商的工作原理是看着每一位,并返回1,如果该位是其中一个输入1.所以:
0011 | 0101 = 0111
Run Code Online (Sandbox Code Playgroud)
如果一个输入中的位为0,则从另一个输入获得该位.看看(age << 8),(gender << 7)并且height,你会看到,如果其中一个的位为1,则其他的为0.所以:
packed_info = (age << 8) | (gender << 7) | height = AAAAAAAGHHHHHHH
Run Code Online (Sandbox Code Playgroud)
现在我们要解压缩位.让我们从高度开始吧.我们想得到最后7位,并忽略前8位.为此,我们使用&运算符,只有当两个输入位都是1时才返回1.所以:
0011 & 0101 = 0001
Run Code Online (Sandbox Code Playgroud)
所以:
packed_info = AAAAAAAGHHHHHHH
0x7F = 000000001111111
(packed_info & 0x7F) = 00000000HHHHHHH = height
Run Code Online (Sandbox Code Playgroud)
为了达到这个年龄,我们可以将所有8个位置推到右边,我们就离开了0000000AAAAAAAA.所以age = (packed_info >> 8).
最后,为了获得性别,我们将所有7个位置推到右边以摆脱高度.然后我们只关心最后一点:
packed_info = AAAAAAAGHHHHHHH
(packed_info >> 7) = 0000000AAAAAAAG
1 = 000000000000001
(packed_info >> 7) & 1 = 00000000000000G
Run Code Online (Sandbox Code Playgroud)
And*_*ite 12
这可能是比特操纵的一个相当长的教训,但首先让我指出维基百科上的位掩盖文章.
packed_info = (age << 8) | (gender << 7) | height;
Run Code Online (Sandbox Code Playgroud)
取出年龄并将其值移动超过8位然后取出性别并将其移动超过7位,高度将占据最后一位.
age = 0b101
gender = 0b1
height = 0b1100
packed_info = 0b10100000000
| 0b00010000000
| 0b00000001100
/* which is */
packed_info = 0b10110001100
Run Code Online (Sandbox Code Playgroud)
解包反过来但使用像0x7F(0b 01111111)这样的掩码来修剪字段中的其他值.
gender = (packed_info >> 7) & 1;
Run Code Online (Sandbox Code Playgroud)
会像...一样工作
gender = 0b1011 /* shifted 7 here but still has age on the other side */
& 0b0001
/* which is */
gender = 0b1
Run Code Online (Sandbox Code Playgroud)
注意,将任何东西与1进行AND运算与"保持"该位相同,而使用0进行AND运算与"忽略"该位相同.
如果要将日期存储为数字,则可以通过将年份乘以10000,月份乘以100并加上日期来实现。诸如2011年7月2日这样的日期将被编码为数字20110702:
year * 10000 + month * 100 + day -> yyyymmdd
2011 * 10000 + 7 * 100 + 2 -> 20110702
Run Code Online (Sandbox Code Playgroud)
可以说,我们使用yyyymmdd掩码对日期进行了编码。我们可以将此操作描述为
这与年龄,性别和身高编码相同,只是作者以二进制的方式思考。
查看这些值可能具有的范围:
age: 0 to 127 years
gender: M or F
height: 0 to 127 inches
Run Code Online (Sandbox Code Playgroud)
如果将这些值转换为二进制,我们将有:
age: 0 to 1111111b (7 binary digits, or bits)
gender: 0 or 1 (1 bit)
height: 0 to 1111111b (7 bits also)
Run Code Online (Sandbox Code Playgroud)
考虑到这一点,我们可以使用掩码aaaaaaaghhhhhhh编码年龄-性别-高度数据,仅是在这里我们谈论的是二进制数字,而不是十进制数字。
所以,
对于二进制,Shift-Left运算符(<<)将值向左移动n个位置。“或”运算符(在许多语言中为“ |”)将值组合在一起。因此:
(age << 8) | (gender << 7) | height
Run Code Online (Sandbox Code Playgroud)
现在,如何“解码”这些值?
用二进制比用十进制更容易:
Shift-Right运算符(>>)将值向右移动n个位置(无论从最右边的位置“移出”的数字丢失了)。“ And”二进制运算符(在许多语言中为“&”)可屏蔽位。为此,它需要一个掩码,指示要保留的位和要销毁的位(保留1位)。因此:
height = value & 1111111b (preserve the 7 rightmost bits)
gender = (value >> 1) & 1 (preserve just one bit)
age = (value >> 8)
Run Code Online (Sandbox Code Playgroud)
由于在大多数语言中,十六进制的1111111b为0x7f,因此才有了该魔术数字。使用127(十进制为1111111b)将具有相同的效果。
小智 5
同样的要求我已经遇到过很多次了。借助按位与运算符,这非常容易。只需用二 (2) 的递增幂来限定您的值即可。要存储多个值,请将它们的相对数(2 的幂)相加并获得 SUM。此 SUM 将合并您选择的值。如何 ?
只需对每个值执行按位与操作,对于未选择的值将给出零 (0),对于选择的值将给出非零。
解释如下:
1) 价值观(是、否、也许)
2) 2 的幂赋值(2)
YES = 2^0 = 1 = 00000001
NO = 2^1 = 2 = 00000010
MAYBE = 2^2 = 4 = 00000100
Run Code Online (Sandbox Code Playgroud)
3)我选择“是”和“可能”,因此选择“SUM”:
SUM = 1 + 4 = 5
SUM = 00000001 + 00000100 = 00000101
Run Code Online (Sandbox Code Playgroud)
该值将存储 YES 和 MAYBE。如何?
1 & 5 = 1 ( non zero )
2 & 5 = 0 ( zero )
4 & 5 = 4 ( non zero )
Run Code Online (Sandbox Code Playgroud)
因此 SUM 包括
1 = 2^0 = YES
4 = 2^2 = MAYBE.
Run Code Online (Sandbox Code Playgroud)
更详细的解释和实现请访问我的博客