我知道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)
方法相比,此方法是否有任何特殊功能,以及它是如何工作的。
答案 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之间的间距不同。
补码运算有两条规则:
使用补码,符号位和其他位可以统一处理。
当两个互补数相加时,如果最高位(符号位)有进位,则丢弃进位。
总而言之,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读取为无符号整数,然后将答案作为整数中的一般比较函数返回。