如何将一个字节的前 n 位与另一个字节的后 8-n 位合并?
我知道像下面这样从第一位选择 3 位,从第二位选择 5 位(我在 DES 加密算法中观察到)
zByte=(xByte & 0xE0) | (yByte & 0x1F);
但我不知道为什么我们需要在这种情况下使用 0XE0 和 0X1F 背后的数学。所以我试图了解每一位的细节。
在 C# 中,这将类似于:
int mask = ~((-1) << n);
var result = (x & ~mask) | (y & mask);
即,我们构建一个掩码,即(对于 n = 5)000....0011111
:,然后我们将(&
)一个操作数与该掩码组合,将另一个操作数与掩码的逆(~
)组合,并将它们组合(|
)。
您也可以仅使用移位操作(完全避免使用掩码)更快地做一些事情 - 但前提是数据可以被视为unsigned
(因此 Java 可能会在这里遇到困难)。
听起来你不明白布尔算术是如何工作的?如果这是您的问题,它的工作原理如下:
0xEO
并且0x1F
是数字的十六进制表示。如果我们将这些数字转换为二进制,它们将是:
0xE0 = 11100000
0x1F = 00011111
另外 & (and) 和 | (or) 是按位逻辑运算符。要理解逻辑运算符,首先要记住 1 = true 和 0 = false。
& 的真值表是:
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
真值表| 是:
0 | 0 = 0
0 | 1 = 1
1 | 0 = 1
1 | 1 = 1
因此,让我们逐个分解您的方程式。首先,我们将首先评估括号中的代码。我们将遍历二进制中的每个数字,对于 & 运算符,如果每个操作数在相同的位上都有一个 1,我们将返回 1。如果任何一个数字有一个 0,那么我们将返回 0。在我们完成对操作数的求值后括号中我们将得到 2 个结果数字并应用 | 操作员一点一点。如果任一数字在相同的位位置有 1,我们将返回 1。如果两个数字在相同的位位置有 0,我们将返回 0。
为了讨论,让我们说
xByte = 255 or (FF in hex and 11111111 in binary)
yByte = 0 or (00 in hex and 00000000 in binary)
当你应用 & 和 | 我们将一次比较每个位的运算符:
zByte = (xByte & 0xEO) | (yByte & 0x1F)
变成:
zByte = (11111111 & 11100000) | (00000000 & 00011111)
zByte = 111000000 | 00000000
zByte = 11100000
如果您了解这一点以及布尔逻辑的工作原理,那么您可以使用Marc Gravell的答案。
这些数字(0xE0 和 0x1F)背后的数学原理非常简单。0 & <bit>
首先,我们利用always equals0
和1 & <bit>
always equals的事实<bit>
。
0x1F 是 00011111 二进制,这意味着在对另一个字节进行 & 操作后,前 3 位将始终为 0 - 最后 5 位将与它们在另一个字节中的相同。请记住,二进制数中的每个 1 代表 2 的幂,因此,如果您想在数学上找到掩码,它将是从 x = 0 到 n-1 的 2^x 的总和。然后您可以找到相反的掩码(即 11100000)来提取前 3 位,您只需从 11111111 中减去掩码,您将得到 11100000(0xE0)。
在java中,
通过使用以下函数,我们可以获得第一个字节的前 n 位和第二个字节的后 8 n 位。
公共类 BitExample {
public static void main(String[] args) {
Byte a = 15;
Byte b = 16;
String mergedValue=merge(4, a, b);
System.out.println(mergedValue);
}
public static String merge(int n, Byte a, Byte b) {
String mergedString = "";
String sa = Integer.toBinaryString(a);
String sb = Integer.toBinaryString(b);
if(n>sa.length()) {
for(int i=0; i<(n-sa.length()); i++) {
mergedString+="0";
}
mergedString+=sa;
}else{
mergedString+=sa.substring(0, n);
}
if(8*n>sb.length()) {
for(int i=0; i<(8*n-sb.length()); i++) {
mergedString+="0";
}
mergedString+=sb;
}
return mergedString;
}
}