【问题标题】:Understanding signed numbers and complements in java理解java中的有符号数和补码
【发布时间】:2013-02-04 19:53:18
【问题描述】:

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

【问题讨论】:

    标签: java byte bit sign complement


    【解决方案1】:

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

    【讨论】:

    • 是的,谢谢,我知道这很简单。您的答案正是我一直在寻找的,因此我将其标记为解决方案,但知道为什么我必须在该数字上加 1 才能获得所需的结果吗?
    • 在二进制补码中,~x == -x - 1。所以这可能是一个人的补码的神器。
    【解决方案2】:

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

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

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

    【讨论】:

    • 感谢您的快速响应...当您说“0xFFEE1B17 是 -1172713”时,您的意思是什么数字的补码?
    • @rjcarr:几乎所有系统(以及java)都使用2-compliment
    【解决方案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;
    

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

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

    请注意,java 还有一个无符号右移运算符&gt;&gt;&gt;。有关详细信息,请参阅 Java 教程:Bitwise and Bit Shift Operators

    【讨论】:

    • @MrSmith42 感谢您指出这一点,我已经更正了。当然应该是按位和/或。
    猜你喜欢
    • 2015-07-04
    • 1970-01-01
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 2021-03-27
    • 1970-01-01
    • 2014-02-23
    • 1970-01-01
    相关资源
    最近更新 更多