4

I know compare(int a, int b) returns 1 if a > b, 0 if a == b, -1 a < b. When I faced to compareUnsigned() didn't get how does it function. I have done some research on the documentation of this method in IntelliJ Idea about this method and found out how does
compareUnsigned() static method work after it receives integer x and y as arguments :

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

Could anyone explain if there is any special feature of this method compared to compare(int a, int b) method and how does it do .

Nodirxon
  • 99
  • 9
  • Please clarify your question. Might you be confusing operators (+ - / *) with functions/methods? – Andrew Fan Dec 11 '18 at 06:14
  • Uh I never seen this method, Can you provide the docs to what this is part of? edit: nvm looks like It's a static method instead of instance. But I have never heard of it. – SamHoque Dec 11 '18 at 06:16

5 Answers5

4

This may not be a perfect answer as I'm not really sure exactly what Java does when you call Integer.compareUnsigned(-1, 2) but I will try explain what I think is happening.

First I will like to point out that

Integer.compareUnsigned(-1, 2)

returns 1 which indicates -1 is greater than 2. Why is what I'll try to explain here.

Integer.compare(int, int)

Just does normal integer comparison as you would do manually.

Before explaining Integer.compareUnsigned(int, int) let's look at what signed and unsigned ints are.

Java uses 32 bits to store integers. This means an int variable can represent up to 2^32 numbers. The range of values will depend on the integer representation used.

For unsigned integers this will be 0 through 4,294,967,295 (2^32 − 1). Which means the minimum unsigned integer on a 32 bit system is 0 and the maximum unsigned integer on 32 bit system is 4,294,967,295.

For signed integers will be −2,147,483,648 (−2^31) through 2,147,483,647 (2^31 − 1) for representation as two's complement.

Now you see that -1 doesn't exist in the unsigned representation. In languages like C that have unsigned type. When you do unsigned int x = -1; On my 64 bit Intel based Mac (I am specific here because unlike Java, C is a little bit implementation specific), -1 is converted to 4294967295 which is the largest value of a unsigned integer. -2 is converted to 4294967294 which is just one less than the largest value of an unsigned integer.

#include <stdio.h>

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

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

Output

x = 4294967295 
y = 4294967294

Now you see that negative numbers are been converted to a signed equivalent in C. How that is done I'm not really sure but you can have a look at this answer to understand it more https://stackoverflow.com/a/7152835/4801462

So when you call Integer.compareUnsigned(-1, 2), my guess is that Java tries to treat -1 as an unsigned int. Which means -1 will be converted to non negative value before the comparison is done. How that is done I'm not really sure as the documentation doesn't say but you shouldn't count on that. Why do I say so?

Java does NOT have an unsigned type and an int in Java is capable of holding a positive maximum value of 2,147,483,647 (2^31 − 1) which is about half the maximum value of an unsigned int. So even if -1 is to be treated as an unsigned int, it will probably overflow the int variable which will cause something other than the unsigned version of -1 to be stored in that variable.

My advice is, avoid using that method unless you are 100% what you are doing.

NB

A more experienced person will probably have a better answer. I've never used this method. I just applied knowledge I learned from college 4 years ago to answer this question.

References:

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

EDIT

What Java could be doing when you send in -1 in Integer.compareUnsigned(int, int) is get the unsigned equivalent of -1 and store it inside a long since it might overflow an int then do the comparison.

Stylishcoder
  • 1,142
  • 1
  • 11
  • 21
3

The range of signed int values is -2^31 to 2^31-1. The value 0 is in the middle.

The range of unsigned int is 0 to 2^32-1 with 0 being the lowest number.

Both have 2^32 values, the difference is which representation is the lowest and highest.

By shifting all the values by -2^31, ( e.g. 0, lowest unsigned ==> -2^31, lowest signed ) the unsigned range is shifted to the signed range and the comparisons like < <= >= > == != all work for unsigned as they do for signed.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
2

For this you should understand the difference between signed and unsigned integers, this is a basic concept you come across when studying datatypes in C and C++ but in java it is hardly used. An unsigned integer is one where the compiler treats an integer as if it is always positive. For example, The binary code of 10 is 01010.(5 bits) The binary code of -10 will be 11010,

The first bit represents sign of the value. 0 means positive and 1 means negative.

What unsigned does is it will read -10 as 26(11010 without sign bit is the binary code of 26)

So what compareUnsigned(int x, int y) does is that it reads x and y as unsigned integers and then returns the answer as a general compare function in Integer.

  • 1
    Due to your thorough explanation, I have realized what I needed. Thanks all of you for your help. Every comment taught me something. Appreciate! – Nodirxon Dec 11 '18 at 16:40
1

Okay so I have dug into the source for both methods. This is what the java docs has to say for it.

/**
 * 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
 */

So It's treating the values as unsigned and then comparing them. This is the code for it.

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

If we take a look at this SO post we can see what unsigned values actually means

Quoting what Pubby has said in the SO post I just linked above we can understand

A signed integer can represent negative numbers; unsigned cannot.

Signed integers have undefined behavior if they overflow, while unsigned integers wrap around using modulo.

For more info you should check out his answer here

SamHoque
  • 2,978
  • 2
  • 13
  • 43
1

Maybe I have solved the question. The range of signed int values is -2^31 to 2^31-1. The range of unsigned int values is 0 to 2^32-1. The difference of them is whether the highest bit is a sign.

Note that Java does not have an unsigned type.

We can see the two's complement representation of i by Integer.toBinaryString(i), and the zero-bits on the left may be omitted.

The range can be divided two intervals, i.e., [-2^31,-1] and [0,2^31-1]. Any interval can be generated by another interval plus Integer.MIN_VALUE. Examples are shown in the table below.

The first column is the original value and the second column is its two's complement representation. The third column is the value which is the original value add Integer.MIN_VALUE, and the fourth column is its two's complement representation. The second and fourth column are both 32 bits, and it's just that the spacing between 0-1 and 0-0 is different.

There are two rules of complement operation:

  1. Using complement, the symbol bit and other bits can be unified processing.

  2. When two complementary numbers are added, if the highest bit (symbol bit) has a carry, the carry is discarded.

In conclusion, Java uses the signed int to solve the unsigned comparison.

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