字节理解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回答了这个问题并首先回答了,所以我将他作为解决方案。谢谢大家的帮助
# 1 楼答案
如果您想翻转Java int的低三个字节,那么只需执行
^ 0x00FFFFFF
# 2 楼答案
0xFFEE1B17
是1172713
只能添加前导字节FF
如果设置了3字节值的最高位,则00
否则将3字节值转换为适当的
int
的方法可能如下所示:# 3 楼答案
负号被定义为
a + (-a) = 0
。这意味着所有的位都被翻转,然后1
加上。见Two's complement。您可以通过思考添加a + ~a + 1
时会发生什么来检查这个过程是否满足条件你可以识别出一个数字的最高有效位是负数。因此,如果需要将有符号的3字节数转换为4字节数,可以通过检查位来实现,如果设置了位,还可以设置第四个字节的位:
您也可以在一个表达式中实现,这很可能会表现得更好,因为计算中没有分支(分支与当前CPU中的pipelining不兼容):
这里
<<
和>>
执行字节移位。首先,我们将数字8位右移(因此现在它占用3个“上”字节而不是3个“下”字节),然后将其移回。诀窍在于>>
是所谓的Arithmetic shift,也称为符号移位。将最高有效位复制到该操作产生的所有空位。这正是为了保留数字的符号。事实上:只需注意,java还有一个无符号右移运算符
>>>
。有关更多信息,请参阅Java教程:Bitwise and Bit Shift Operators