有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

字节理解java中的有符号数字和补码

我有一个3字节的有符号数字,我需要它来确定Java中的值。我相信它是用一个人的补语签署的,但我不是100%确定(我已经10多年没有研究过这个东西了,而且我的问题的文档也不是非常清楚)。我认为我遇到的问题是Java做的每件事都是二者互补的。我有一个具体的例子来说明:

  • 原始的3字节数字:0xEE1B17

  • 解析为整数(Integer.parseInt(s, 16)),它变成:15604503

  • 如果我做一个简单的位翻转(~),我得到(我想)一个二的补码表示:-15604504

  • 但我应该得到的值是:-1172713

我想发生的是,我得到了整个int的两个补码,而不仅仅是int的3个字节,但我不知道如何解决这个问题

我所能做的是将整数转换为二进制字符串(Integer.toBinaryString()),然后手动将所有0“翻转”为1,反之亦然。当解析这个整数(Integer.parseInt(s, 16))时,我得到了非常接近的1172712。在所有其他例子中,我总是需要在结果中加1才能得到答案

任何人都可以诊断这里使用的是哪种类型的有符号数字编码,以及除了手动翻转字符串的每个字符之外是否有其他解决方案?我觉得必须有一个更优雅的方式来做到这一点

编辑:所有的响应者都以不同的方式提供了帮助,但我的一般问题是如何翻转一个3字节的数字,@louis wasserman回答了这个问题并首先回答了,所以我将他作为解决方案。谢谢大家的帮助


共 (3) 个答案

  1. # 1 楼答案

    如果您想翻转Java int的低三个字节,那么只需执行^ 0x00FFFFFF

  2. # 2 楼答案

    0xFFEE1B171172713 只能添加前导字节FF如果设置了3字节值的最高位,则00否则

    将3字节值转换为适当的int的方法可能如下所示:

    if(byte3val>7FFFFF)
      return byte3val| 0xFF000000;
    else 
      return byte3val;
    
  3. # 3 楼答案

    负号被定义为a + (-a) = 0。这意味着所有的位都被翻转,然后1加上。见Two's complement。您可以通过思考添加a + ~a + 1时会发生什么来检查这个过程是否满足条件

    你可以识别出一个数字的最高有效位是负数。因此,如果需要将有符号的3字节数转换为4字节数,可以通过检查位来实现,如果设置了位,还可以设置第四个字节的位:

    if ((a & 0x800000) != 0)
        a = a | 0xff000000;
    

    您也可以在一个表达式中实现,这很可能会表现得更好,因为计算中没有分支(分支与当前CPU中的pipelining不兼容):

    a = (0xfffffe << a) >> a;
    

    这里<<>>执行字节移位。首先,我们将数字8位右移(因此现在它占用3个“上”字节而不是3个“下”字节),然后将其移回。诀窍在于>>是所谓的Arithmetic shift,也称为符号移位。将最高有效位复制到该操作产生的所有空位。这正是为了保留数字的符号。事实上:

    (0x1ffffe << 8) >> 8        ->  2097150
    (0xfffffe << 8) >> 8        ->  -2
    

    只需注意,java还有一个无符号右移运算符>>>。有关更多信息,请参阅Java教程:Bitwise and Bit Shift Operators