【问题标题】:Merge first n bits of a byte with last 8-n bits of another byte将一个字节的前 n 位与另一个字节的后 8-n 位合并
【发布时间】:2013-10-10 10:27:03
【问题描述】:

如何将一个字节的前 n 位与另一个字节的后 8-n 位合并?

我知道从第一个中选择 3 位,从第二个中选择 5 位(我在 DES 加密算法中观察到)
zByte=(xByte & 0xE0) | (yByte & 0x1F);
但我不知道为什么在这种情况下我们需要使用 0XE0 和 0X1F 背后的数学原理。所以我试图了解每一位的细节。

【问题讨论】:

  • C#Java?选一个。到目前为止,您还尝试过什么?
  • merge 表示串联,AND?OR?
  • 我知道 Java 和 C#,不管我会用哪种语言得到答案。我可以用其他语言解释它。我知道类似下面的内容,用于从第一个中选择 3 位,从第二个中选择 5 位(我在 DES 加密算法中观察到)zByte=(xByte & 0xE0) | (yByte & 0x1F);但我不知道为什么我们需要在这种情况下使用 E0 和 1F 背后的数学。所以我试图了解每一位的细节。 @RajeshSubramanian 我的意思是串联。
  • 这不是串联。

标签: c# java


【解决方案1】:

在 C# 中,应该是这样的:

    int mask = ~((-1) << n);
    var result = (x & ~mask) | (y & mask);

即我们构建一个掩码,即(对于 n = 5):000....0011111,然后我们将(&amp;)一个操作数与该掩码组合,另一个操作数与 inverse~)掩码,然后组合它们 (|)。

您也可以仅使用移位操作(完全避免使用掩码)更快地执行某些操作 - 但前提是数据可以被视为 unsigned(因此 Java 可能会在这里遇到困难)。

【讨论】:

  • 你可以这样制作面具:int mask = 0xff &gt;&gt; n;
  • @LorentzVedeler 给出的例子是 n = 17,那是行不通的。此外,对于全角操作,它需要是无符号的——在 Java 上是有问题的。但是:一个选项本身应该可以正常工作。会更新...更好吗?
  • 是的,这很好。顺便说一句,Java 有一个无符号右移,所以你也可以使用 -1 &gt;&gt;&gt; -n(在 C# 中稍微冗长一些),但属性略有不同(某种意义上的“镜像”属性)。
【解决方案2】:

听起来您似乎不了解布尔运算的工作原理?如果这是您的问题,它的工作方式如下:

0xEO0x1F 是数字的十六进制表示。如果我们将这些数字转换为二进制,它们将是:

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 的答案。

【讨论】:

  • 你好兄弟...我知道真值表,我知道什么是十六进制、二进制和任何其他格式。我想你没有理解我的问题。你能告诉我如何从一个字节中提取前 2 位或后 2 位吗?然后我会从那里开始管理......
  • @SudhakarChavali 提取位,您通常使用掩码“和”,就像每个人一直在说的那样......
【解决方案3】:

这些数字(0xE0 和 0x1F)背后的数学原理非常简单。首先,我们利用0 &amp; &lt;bit&gt; 始终等于01 &amp; &lt;bit&gt; 始终等于&lt;bit&gt; 的事实。

0x1F 是 00011111 二进制,这意味着在与另一个字节进行 & 操作后前 3 位将始终为 0 - 最后 5 位将与它们在另一个字节中的相同。请记住,二进制数中的每个 1 代表 2 的幂,因此,如果您想在数学上找到掩码,它将是从 x = 0 到 n-1 的 2^x 的总和。然后你可以找到相反的掩码(即11100000)来提取前3位,你只需从11111111中减去掩码,你会得到11100000(0xE0)。

【讨论】:

    【解决方案4】:

    在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;
    }
    

    }

    【讨论】:

    • 这很可能是我见过的执行位操作的最不必要的复杂方式。计算机设计是为了处理比特 - 将所有内容都作为字符串处理本质上也称为“做错事”。
    • 好的,感谢您的宝贵回复,我们会努力提高我的位操作技能。
    猜你喜欢
    • 2013-02-21
    • 2012-08-21
    • 2010-11-19
    • 1970-01-01
    • 2013-09-09
    • 2017-05-27
    • 2012-11-16
    • 2023-02-24
    • 1970-01-01
    相关资源
    最近更新 更多