【问题标题】:How do I compare two longs as unsigned in Java?如何在 Java 中比较两个 long 作为 unsigned?
【发布时间】:2010-11-27 12:22:18
【问题描述】:

我将无符号 64 位数字的位模式存储在 long 变量中,并希望计算其中两个在无符号范围内的距离。因为 Java 将 long 解释为二进制补码有符号整数,所以我不能只使用 a - b,如下例所示:

// on the unsigned range, these numbers would be adjacent
long a = 0x7fffffffffffffffL;
long b = 0x8000000000000000L;

// but as two's complement (or any representation that 
// stores the sign in the first bit), they aren't
assert b - a == 1;

这样做的正确方法是什么?

【问题讨论】:

  • 正如下面几位海报所指出的,我的示例确实有效。我从应用程序中更复杂的代码中提取了它,之后没有对其进行测试,后来发现我在原始代码中有另一个错误,这让我相信二进制表示是问题所在。这意味着这个问题不再有意义。但是,这些答案对我很有帮助,所以我就让它保持原样。
  • 我想我记得有一个答案以二进制形式显示我以后如何使用计算出的差异来通过b = a + d 检索 b,以及为什么为此目的,你怎么做并不重要解释位模式。但是那个答案要么消失了,要么我在其他地方看到了。尽管如此,它还是有帮助的。 ;-)

标签: java bit-manipulation math


【解决方案1】:

随着算术运算的结束,对于您给出的情况,它的结果是一样的。如果您将结果解释为无符号值,则适用于所有情况 - 您只是更改位模式的解释,它仍然是 Z264.

【讨论】:

    【解决方案2】:

    Java 8 开始,long 作为无符号整数的比较可以通过Long.compareUnsigned(x, y) 完成。

    以下是 Java 7 及更早版本的简单反向移植:

    public static int compareUnsigned(long x, long y) {
       return Long.compare(x + Long.MIN_VALUE, y + Long.MIN_VALUE);
    }
    

    【讨论】:

      【解决方案3】:

      如果您正在处理加法和减法,则使用有符号或无符号类型并不重要,只要参数都是有符号的或都是无符号的。如果需要比较 a 和 b,请将 a-b 与 0 进行比较。

      【讨论】:

      • 加减法真的是我唯一需要的。我存储增量,以便以后从中重建原始值。
      • @Adam 如果您需要比较 a 和 b,请将 a-b 与 0 进行比较 - 我认为这行不通。为简单起见,考虑a=0x80b=0x7F 之间的无符号byte 比较。以签名条款a = -128b = 127。现在 a-b > 0 应该是 true 如果它们是无符号的,但它不是在 Java 中,因为类型 byte 是有符号的。
      • @Aravind 字节示例不起作用,因为在 Java 中,字节在执行算术之前会向上转换为整数。在这种情况下,您将使用 (byte)(a-b),这对于 a=0x80 和 b=0x7f 将产生 1。
      • 我不明白你。如果 a 是一个小幅度的正数,而 b 是一个稍微大一点的负数,那么 a - b > 0 会给出肯定的答案,如果您将输入视为有符号,这是正确的。但是,如果我们认为它们都是无符号的,那么 b 实际上是一个很大的正数,并且 a - b > 0 应该是假的。
      • @AdamCrume 您的答案部分正确-仅当您检查 a 和 b 是否相等时。常见的比较案例要复杂得多,如下面的一些答案所示
      【解决方案4】:

      为我工作:

      long a = 0x7fffffffffffffffL;
      long b = 0x8000000000000000L;
      b - a = (long) 1
      a - b = (long) -1
      

      【讨论】:

      • 完全正确,我从中提取示例的代码中存在错误。请参阅我上面的评论。
      【解决方案5】:

      我使用了这个解决方案:

      if (longA == longB) return 0;
      return (longA < longB) ^ (longA < 0) ^ (longB< 0) ? 1 : -1;
      

      All credits go to this website

      【讨论】:

        【解决方案6】:

        如前所述,减法不会有问题,所以如果这就是你想要做的,那就不用担心。

        但是,以您的示例为例,加法会溢出,并且任何关系运算符都不能正常工作。如果这是一个问题,那么您可以编写自己的关系操作,或者使用比 Long 更好的框类型。

        解决方案: 1. 使用 BigInteger 而不是 Long。 BigInteger 是为进行大数计算而创建的,可以轻松支持 128 位计算。

        1. 编写您自己的关系运算并排除使用加法或乘法的可能性。编写自己的关系运算符真的没那么难。首先你比较最重要的位。如果两个数字的最高有效位相同,您可以通过按位和 (&) 与 0X7FFFFFFFFFFFFFFF 进行屏蔽,然后比较屏蔽后的值。

        【讨论】:

          【解决方案7】:

          我使用以下代码:

          static boolean unsignedLessThan(long left, long right) { 
              return (left < right) ^ (left < 0) ^ (right < 0);
          }
          

          (基于 Tamutnefret 的示例)

          【讨论】:

            【解决方案8】:

            【讨论】:

            • darksleep 提供的解决方法是将签名类型转换为使用两倍字节数的类型,例如使用 short(2 字节)来保存无符号字节,或使用 int(4 字节)来保存无符号短。但是,Java 没有内置的 16 字节数字类型,OP 可以使用它来存储无符号长整数(8 字节)。
            【解决方案9】:

            显然你需要处理比特。

            static boolean compare(long a, long b)
            {
                if(( a &  (Long.MAX_VALUE + 1)) != 0)
                    return ( b & (Long.MAX_VALUE + 1) )  != 0
                        ? (a < b) //same sign 
                        : true; //a is greater b
                else 
                    return ( b & (Long.MAX_VALUE + 1) )  != 0
                        ? false //b is greater a
                        : a < b; //same sign
            }
            

            【讨论】:

            • 在比较 static boolean compare(long a, long b) { return a^0x8000000000000000L &lt; b^0x8000000000000000L; } Long.compare(a^0x8000000000000000L, b^0x8000000000000000L) 之前将无符号空间 [0,2^64-1] 映射到有符号空间 [2^63,2^63-1] 就足够了
            【解决方案10】:

            或者你可以这样做一半一半,

            public static long unsignedDiff(long a, long b) {
                long mask = 0xFFFFFFFFL;
                return (( ((a >> 32) & mask) - ((b >> 32) & mask) ) << 32) +
                   + ((a & mask) - (b & mask));
            }
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-08-17
              • 2016-04-19
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多