1

我有一个 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 回答了这个问题并首先回答了,所以我将他标记为解决方案。感谢大家的帮助!

4

3 回答 3

2

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

于 2013-02-04T19:59:11.147 回答
1

0xFFEE1B17is -1172713 您必须只添加前导字节。FF如果设置了 3 字节值的最高位,00否则。

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

if(byte3val>7FFFFF)
  return byte3val| 0xFF000000;
else 
  return byte3val;
于 2013-02-04T19:59:49.880 回答
0

负符号数是这样定义的a + (-a) = 0。所以这意味着所有位都被翻转然后1相加。请参阅二进制补码。您可以通过考虑添加时发生的情况来检查此过程是否满足条件a + ~a + 1

您可以通过其最高有效位识别出一个数字是否为负数。因此,如果您需要将带符号的 3 字节数字转换为 4 字节数字,您可以通过检查该位来完成,如果已设置,则还设置第四个字节的位:

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

您也可以在单个表达式中执行此操作,这很可能会执行得更好,因为计算中没有分支(在当前 CPU 中,分支与流水线处理效果不佳):

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

在这里<<执行>>字节移位。首先我们将数字向右移动 8 位(所以现在它占据了 3 个“高”字节而不是 3 个“低”字节),然后将其移回。诀窍是>>所谓的算术移位,也称为有符号移位。将最高有效位复制到由操作空置的所有位。这正是为了保留数字的符号。确实:

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

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

于 2013-02-04T20:08:23.433 回答