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

理解java中的有符号数和补码,java,byte,bit,sign,complement,Java,Byte,Bit,Sign,Complement,我有一个3字节的有符号数字,我需要它来确定Java中的值。我相信它是用一个人的补语签署的,但我不是100%确定(我已经10多年没有研究过这个东西了,而且我的问题的文档也不是非常清楚)。我认为我遇到的问题是Java做的每件事都是二者互补的。我有一个具体的例子来说明: 原始3字节数字:0xEE1B17 解析为一个整数(integer.parseInt(s,16)),它变成:15604503 如果我做一个简单的位翻转(~),我得到(我想)一个2的补码表示:-15604504 但我应该得到的值是:-1

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

  • 原始3字节数字:
    0xEE1B17

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

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

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

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

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

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


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

如果要翻转Java int的低位三个字节,只需执行
^0x00FFFFFF
0xFFEE1B17
is-
1172713
只能添加前导字节
FF
如果设置了3字节值的最高位,则
00
否则

将3字节值转换为正确的
int
的方法如下所示:

if(byte3val>7FFFFF)
  return byte3val| 0xFF000000;
else 
  return byte3val;

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

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

if ((a & 0x800000) != 0)
    a = a | 0xff000000;
您也可以在单个表达式中执行此操作,这很可能会表现得更好,因为计算中没有分支(分支在当前CPU中不起作用):


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

是的,谢谢,我知道这会很简单。你的答案正是我想要的,所以我将它标记为解决方案,但是你知道为什么我必须在这个数字上加1才能得到想要的结果吗?在2的补码中,
~x==-x-1
。所以,这可能是一个人补语的产物。谢谢你们的快速回复。。。当你在什么数字的补码中说“0xFFEEB17是-1172713”时,你是什么意思?@rjcarr:the在几乎所有的系统(以及java)中都使用@MrSmith42谢谢你指出了这一点,我已经纠正了它。当然,它应该是按位和/或。
a = (0xfffffe << a) >> a;
(0x1ffffe << 8) >> 8        ->  2097150
(0xfffffe << 8) >> 8        ->  -2