我有一个3字节的有符号数,我需要确定Java中的值。我相信它是用一个补码签名但我不是100%肯定(我已经十多年没研究过这个东西了,我的问题的记录并不是很清楚)。我认为我遇到的问题是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回答了这个并首先回答,所以我将他标记为解决方案。感谢大家的帮助!答案 0 :(得分:2)
如果要翻转Java int的低三个字节,那么只需执行^ 0x00FFFFFF
。
答案 1 :(得分:1)
0xFFEE1B17
是 - 1172713
您只能添加前导字节。如果设置了3字节值的最高位,则FF
,否则为00
。
将3字节值转换为适当的int
的方法可能如下所示:
if(byte3val>7FFFFF)
return byte3val| 0xFF000000;
else
return byte3val;
答案 2 :(得分:0)
定义负的有符号数字,以便a + (-a) = 0
。因此,这意味着所有位都被翻转,然后添加1
。见Two's complement。您可以通过考虑添加a + ~a + 1
时发生的情况来检查此过程是否满足条件。
您可以通过最重要的位识别出一个数字为负数。因此,如果需要将带符号的3字节数转换为4字节数,可以通过检查该位来实现,如果设置了,则还要设置第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。