【问题标题】:What is the difference between compare() and compareUnsigned() in JavaJava中的compare()和compareUnsigned()有什么区别
【发布时间】:2018-12-11 06:09:07
【问题描述】:

我知道compare(int a, int b) 如果a > b 返回 1,如果a == b 返回 0,-1 a < b。当我面对compareUnsigned() 时,我不知道它是如何工作的。我在 IntelliJ Idea 中对此方法的文档进行了一些研究,发现了
compareUnsigned() 静态方法在接收整数 x 和 y 作为参数后如何工作:

public static int compareUnsigned(int x, int y) {
        return compare(x + -2147483648, y + -2147483648);
    }

谁能解释一下这种方法与compare(int a, int b) 方法相比是否有什么特殊之处以及它是如何做的。

【问题讨论】:

  • 请澄清您的问题。您可能会将运算符 (+ - / *) 与函数/方法混淆吗?
  • 呃,我从来没有见过这种方法,你能提供文档说明这是什么的一部分吗?编辑:nvm 看起来像是一个静态方法而不是实例。但我从来没有听说过。

标签: java


【解决方案1】:

这可能不是一个完美的答案,因为我不太确定 Java 在调用 Integer.compareUnsigned(-1, 2) 时究竟做了什么,但我会尝试解释我认为正在发生的事情。

首先我要指出的是

Integer.compareUnsigned(-1, 2)

返回 1,表示 -1 大于 2。为什么我会在这里解释。

Integer.compare(int, int)

就像手动进行一般的整数比较。

在解释 Integer.compareUnsigned(int, int) 之前,让我们先看看有符号整数和无符号整数是什么。

Java 使用 32 位来存储整数。这意味着int 变量最多可以表示 2^32 个数字。值的范围取决于所使用的整数表示。

对于无符号整数,这将是 0 到 4,294,967,295 (2^32 − 1)。这意味着 32 位系统上的最小无符号整数是 0,而 32 位系统上的最大无符号整数是 4,294,967,295。

对于有符号整数将是 -2,147,483,648 (-2^31) 到 2,147,483,647 (2^31 - 1) 以表示为二进制补码。

现在您看到 -1 在无符号表示中不存在。在像 C 这样具有无符号类型的语言中。当你做 unsigned int x = -1;在我的 64 位基于 Intel 的 Mac 上(我在这里比较具体,因为与 Java 不同,C 有点特定于实现),-1 被转换为 4294967295,它是无符号整数的最大值。 -2 转换为 4294967294,仅比无符号整数的最大值小 1。

#include <stdio.h>

int main() {
    unsigned int x = -1;
    unsigned int y = -2;

    printf("x = %u\ny = %u\n", x, y);
    return 0;   
}

输出

x = 4294967295 
y = 4294967294

现在您看到在 C 中将负数转换为带符号的等价物。我不太确定这是如何完成的,但您可以查看这个答案以进一步了解它https://stackoverflow.com/a/7152835/4801462

因此,当您调用 Integer.compareUnsigned(-1, 2) 时,我的猜测是 Java 试图将 -1 视为无符号整数。这意味着 -1 将在比较完成之前转换为非负值。这是如何完成的我不太确定,因为文档没有说,但你不应该指望这一点。为什么这么说?

Java 确实 NOT 具有无符号类型,并且 Java 中的 int 能够保持正的最大值 2,147,483,647 (2^31 − 1),大约是一半unsigned int 的最大值。因此,即使 -1 被视为无符号整数,它也可能会溢出 int 变量,这将导致 -1 的无符号版本以外的内容存储在该变量中。

我的建议是,除非你 100% 做好自己的工作,否则不要使用这种方法。

注意

更有经验的人可能会有更好的答案。我从来没有使用过这种方法。我只是应用了 4 年前从大学学到的知识来回答这个问题。

参考文献:

https://en.wikipedia.org/wiki/32-bit

编辑

当您在 Integer.compareUnsigned(int, int) 中发送 -1 时,Java 可以做的是获取 -1 的无符号等效项并将其存储在 long 中,因为它可能会溢出 int 然后执行比较。

【讨论】:

    【解决方案2】:

    有符号int 值的范围是-2^31 到2^31-1。值 0 在中间。

    无符号int的范围是0到2^32-1,0是最小的数字。

    两者都有 2^32 个值,区别在于哪个表示是最低的和最高的。

    通过将所有值移动 -2^31,(例如 0,最低无符号 ==> -2^31,最低有符号),无符号范围移动到有符号范围,比较像 &lt; &lt;= &gt;= &gt; == != 对未签名的所有工作都像对签名一样工作。

    【讨论】:

      【解决方案3】:

      为此,您应该了解有符号整数和无符号整数之间的区别,这是您在学习 C 和 C++ 中的数据类型时遇到的一个基本概念,但在 java 中它很少使用。无符号整数是编译器将整数视为始终为正的整数。 例如, 10的二进制码是01010。(5位) -10的二进制码是11010,

      第一位代表值的符号。 0 表示正数,1 表示负数。

      unsigned 的作用是将 -10 读取为 26(没有符号位的 11010 是 26 的二进制代码)

      那么 compareUnsigned(int x, int y) 所做的就是将 x 和 y 读取为无符号整数,然后将答案作为 Integer 中的一般比较函数返回。

      【讨论】:

      • 由于您的详尽解释,我已经意识到我需要什么。谢谢大家的帮助。每一条评论都教会了我一些东西。欣赏!
      【解决方案4】:

      好的,我已经挖掘了这两种方法的来源。这就是 java 文档所要说的。

      /**
       * Compares two {@code long} values numerically treating the values
       * as unsigned.
       *
       * @param  x the first {@code long} to compare
       * @param  y the second {@code long} to compare
       * @return the value {@code 0} if {@code x == y}; a value less
       *         than {@code 0} if {@code x < y} as unsigned values; and
       *         a value greater than {@code 0} if {@code x > y} as
       *         unsigned values
       * @since 1.8
       */
      

      所以它将值视为无符号,然后比较它们。这是它的代码。

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

      如果我们看一下this SO 帖子,我们可以看到无符号值的实际含义

      引用我刚刚在上面链接的 SO 帖子中 Pubby 所说的话,我们可以理解

      有符号整数可以表示负数;无符号不能。

      有符号整数在溢出时具有未定义的行为,而 无符号整数使用模数环绕。

      有关更多信息,您应该查看他的回答here

      【讨论】:

        【解决方案5】:

        也许我已经解决了这个问题。有符号 int 值的范围是 -2^31 到 2^31-1。 unsigned int 值的范围是 0 到 2^32-1。它们的区别在于最高位是否为符号。

        请注意,Java 没有无符号类型。

        我们可以看到Integer.toBinaryString(i)i的二进制补码表示,左边的零位可以省略。

        范围可以分为两个区间,即[-2^31,-1]和[0,2^31-1]。任何间隔都可以由另一个间隔加上 Integer.MIN_VALUE 生成。示例如下表所示。

        第一列是原始值,第二列是它的二进制补码表示。第三列是原始值加 Integer.MIN_VALUE 的值,第四列是它的二进制补码表示。第二列和第四列都是32位,只是0-1和0-0的间距不同而已。

        补码运算有两条规则:

        1. 使用补码,符号位和其他位可以统一处理。

        2. 当两个互补数相加时,如果最高位(符号位)有进位,则丢弃该进位。

        综上所述,Java 使用有符号的 int 来解决无符号的比较。

        The original value two's complement The result value two's complement
        -2^31 10000000000000000000000000000000 0 0000000000000000000000000000000
        -1 11111111111111111111111111111111 2^31-1 01111111111111111111111111111111
        ... ... ... ...
        0 00000000000000000000000000000000 -2^31 10000000000000000000000000000000
        2^31-1 01111111111111111111111111111111 -1 11111111111111111111111111111111

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-09-25
          • 2011-07-30
          • 2011-11-23
          • 2022-12-04
          相关资源
          最近更新 更多