Java中compare()和compareUnsigned()有什么区别

时间:2018-12-11 06:09:07

标签: java

我知道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)方法相比,此方法是否有任何特殊功能,以及它是如何工作的。

5 个答案:

答案 0 :(得分:1)

好的,所以我已经探究了这两种方法的来源。这就是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帖子中Pubby所说的,我们可以理解

  

带符号整数可以表示负数;未签名不能。

     

如果有符号整数溢出,则它们具有不确定的行为,而   无符号整数使用模数进行环绕。

有关更多信息,请查看他的答案here

答案 1 :(得分:1)

这可能不是一个完美的答案,因为我不确定当您调用Integer.compareUnsigned(-1,2)时Java到底会做什么,但是我会尽力解释我的想法。

首先,我想指出一点

Integer.compareUnsigned(-1, 2)

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

Integer.compare(int, int)

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

在解释Integer.compareUnsigned(int,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时;在我的基于Intel的64位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视为未签名的int。这意味着在完成比较之前,-1将转换为非负值。我不确定如何做到这一点,因为文档没有说,但您不应指望这一点。我为什么这么说?

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

我的建议是,除非您的工作量达到100%,否则请避免使用该方法。

NB

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

参考文献:

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

编辑

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

答案 2 :(得分:1)

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

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

两者都有2 ^ 32个值,不同之处在于哪个表示形式是最低和最高。

通过将所有值都移动-2 ^ 31(例如0,最低无符号==> -2 ^ 31,最低有符号),无符号范围将移动到有符号范围,并且比较类似< { {1}} <= >= > ==对未签名的所有工作都与对未签名的工作一样。

答案 3 :(得分:1)

也许我已经解决了这个问题。有符号整数值的范围是 -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 使用有符号整数来解决无符号比较。

<头>
原始值 补码 结果值 补码
-2^31 10000000000000000000000000000000 0 0000000000000000000000000000000
-1 11111111111111111111111111111111 2^31-1 01111111111111111111111111111111
... ... ... ...
0 00000000000000000000000000000000 -2^31 10000000000000000000000000000000
2^31-1 01111111111111111111111111111111 -1 11111111111111111111111111111111

答案 4 :(得分:0)

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

  

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

未签名的意思是它将-10读为26(没有符号位的11010是26的二进制代码)

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