Guava's UnsignedLong: Why does it XOR Long.MIN_VALUE
I was reading Unsigned arithmetic in Java which nicely explained how to do unsigned longs using the following method
public static boolean isLessThanUnsigned(long n1, long n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
However I'm confused by Guava's implementation. I'm hoping someone can shed some light on it.
/**
* A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
* longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
* signed longs.
*/
private static long flip(long a) {
return a ^ Long.MIN_VALUE;
}
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
* @param a the first unsigned {@code long} to compare
* @param b the second unsigned {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
* greater than {@code b}; or zero if they are equal
*/
public static int compare(long a, long b) {
return Longs.compare(flip(a), flip(b));
}
java guava long-integer
add a comment |
I was reading Unsigned arithmetic in Java which nicely explained how to do unsigned longs using the following method
public static boolean isLessThanUnsigned(long n1, long n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
However I'm confused by Guava's implementation. I'm hoping someone can shed some light on it.
/**
* A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
* longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
* signed longs.
*/
private static long flip(long a) {
return a ^ Long.MIN_VALUE;
}
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
* @param a the first unsigned {@code long} to compare
* @param b the second unsigned {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
* greater than {@code b}; or zero if they are equal
*/
public static int compare(long a, long b) {
return Longs.compare(flip(a), flip(b));
}
java guava long-integer
add a comment |
I was reading Unsigned arithmetic in Java which nicely explained how to do unsigned longs using the following method
public static boolean isLessThanUnsigned(long n1, long n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
However I'm confused by Guava's implementation. I'm hoping someone can shed some light on it.
/**
* A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
* longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
* signed longs.
*/
private static long flip(long a) {
return a ^ Long.MIN_VALUE;
}
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
* @param a the first unsigned {@code long} to compare
* @param b the second unsigned {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
* greater than {@code b}; or zero if they are equal
*/
public static int compare(long a, long b) {
return Longs.compare(flip(a), flip(b));
}
java guava long-integer
I was reading Unsigned arithmetic in Java which nicely explained how to do unsigned longs using the following method
public static boolean isLessThanUnsigned(long n1, long n2) {
return (n1 < n2) ^ ((n1 < 0) != (n2 < 0));
}
However I'm confused by Guava's implementation. I'm hoping someone can shed some light on it.
/**
* A (self-inverse) bijection which converts the ordering on unsigned longs to the ordering on
* longs, that is, {@code a <= b} as unsigned longs if and only if {@code flip(a) <= flip(b)} as
* signed longs.
*/
private static long flip(long a) {
return a ^ Long.MIN_VALUE;
}
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
* @param a the first unsigned {@code long} to compare
* @param b the second unsigned {@code long} to compare
* @return a negative value if {@code a} is less than {@code b}; a positive value if {@code a} is
* greater than {@code b}; or zero if they are equal
*/
public static int compare(long a, long b) {
return Longs.compare(flip(a), flip(b));
}
java guava long-integer
java guava long-integer
edited Nov 23 at 10:13
Karol Dowbecki
15.7k82849
15.7k82849
asked Nov 22 at 22:12
Setheron
1,47432244
1,47432244
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
Perhaps some diagrams help. I'll use 8 bit numbers to keep the constants short, it generalizes to ints and longs in the obvious way.
Absolute view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
Relative view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
So signed and unsigned numbers largely have the same relative order, except that the two ranges with the sign bit set and the sign bit not set are swapped in order. Inverting that bit of course swaps the order.
x ^ Long.MIN_VALUE
inverts the sign bit for a long
.
This trick is applicable for any operation that depends only on the relative order, for example comparisons and directly related operations such as min and max. It does not work for operations that depend on the absolute magnitude of the numbers, such as division.
add a comment |
Consider the bits that make up a long
type. Performing ^ Long.MIN_VALUE
converts a regular two's complement signed representation that holds [-263, 263-1] values into an unsigned representation that holds [0, 264-1] values.
You can see the process by taking the smallest long
value, adding one and "flipping" while inspecting the bits (e.g. with Long.toBinaryString()
):
Long.MIN_VALUE ^ Long.MIN_VALUE
is00..00
(all 64 bits unset)
(Long.MIN_VALUE + 1) ^ Long.MIN_VALUE
is00..01
(Long.MIN_VALUE + 2) ^ Long.MIN_VALUE
is00..10
(Long.MIN_VALUE + 3) ^ Long.MIN_VALUE
is00..11
and so on until:
Long.MAX_VALUE ^ Long.MIN_VALUE
is11..11
(all 64 bits set)
The "flip" is done because Longs.compare()
needs input as unsigned [0, 264-1] values as per the method javadoc in your example:
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53438534%2fguavas-unsignedlong-why-does-it-xor-long-min-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Perhaps some diagrams help. I'll use 8 bit numbers to keep the constants short, it generalizes to ints and longs in the obvious way.
Absolute view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
Relative view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
So signed and unsigned numbers largely have the same relative order, except that the two ranges with the sign bit set and the sign bit not set are swapped in order. Inverting that bit of course swaps the order.
x ^ Long.MIN_VALUE
inverts the sign bit for a long
.
This trick is applicable for any operation that depends only on the relative order, for example comparisons and directly related operations such as min and max. It does not work for operations that depend on the absolute magnitude of the numbers, such as division.
add a comment |
Perhaps some diagrams help. I'll use 8 bit numbers to keep the constants short, it generalizes to ints and longs in the obvious way.
Absolute view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
Relative view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
So signed and unsigned numbers largely have the same relative order, except that the two ranges with the sign bit set and the sign bit not set are swapped in order. Inverting that bit of course swaps the order.
x ^ Long.MIN_VALUE
inverts the sign bit for a long
.
This trick is applicable for any operation that depends only on the relative order, for example comparisons and directly related operations such as min and max. It does not work for operations that depend on the absolute magnitude of the numbers, such as division.
add a comment |
Perhaps some diagrams help. I'll use 8 bit numbers to keep the constants short, it generalizes to ints and longs in the obvious way.
Absolute view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
Relative view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
So signed and unsigned numbers largely have the same relative order, except that the two ranges with the sign bit set and the sign bit not set are swapped in order. Inverting that bit of course swaps the order.
x ^ Long.MIN_VALUE
inverts the sign bit for a long
.
This trick is applicable for any operation that depends only on the relative order, for example comparisons and directly related operations such as min and max. It does not work for operations that depend on the absolute magnitude of the numbers, such as division.
Perhaps some diagrams help. I'll use 8 bit numbers to keep the constants short, it generalizes to ints and longs in the obvious way.
Absolute view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
Relative view:
Unsigned number line:
[ 0 .. 0x7F ][ 0x80 .. 0xFF]
Signed number line:
[ 0x80 .. 0xFF ][ 0 .. 0x7F]
So signed and unsigned numbers largely have the same relative order, except that the two ranges with the sign bit set and the sign bit not set are swapped in order. Inverting that bit of course swaps the order.
x ^ Long.MIN_VALUE
inverts the sign bit for a long
.
This trick is applicable for any operation that depends only on the relative order, for example comparisons and directly related operations such as min and max. It does not work for operations that depend on the absolute magnitude of the numbers, such as division.
answered Nov 23 at 2:34
harold
41.2k356108
41.2k356108
add a comment |
add a comment |
Consider the bits that make up a long
type. Performing ^ Long.MIN_VALUE
converts a regular two's complement signed representation that holds [-263, 263-1] values into an unsigned representation that holds [0, 264-1] values.
You can see the process by taking the smallest long
value, adding one and "flipping" while inspecting the bits (e.g. with Long.toBinaryString()
):
Long.MIN_VALUE ^ Long.MIN_VALUE
is00..00
(all 64 bits unset)
(Long.MIN_VALUE + 1) ^ Long.MIN_VALUE
is00..01
(Long.MIN_VALUE + 2) ^ Long.MIN_VALUE
is00..10
(Long.MIN_VALUE + 3) ^ Long.MIN_VALUE
is00..11
and so on until:
Long.MAX_VALUE ^ Long.MIN_VALUE
is11..11
(all 64 bits set)
The "flip" is done because Longs.compare()
needs input as unsigned [0, 264-1] values as per the method javadoc in your example:
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
add a comment |
Consider the bits that make up a long
type. Performing ^ Long.MIN_VALUE
converts a regular two's complement signed representation that holds [-263, 263-1] values into an unsigned representation that holds [0, 264-1] values.
You can see the process by taking the smallest long
value, adding one and "flipping" while inspecting the bits (e.g. with Long.toBinaryString()
):
Long.MIN_VALUE ^ Long.MIN_VALUE
is00..00
(all 64 bits unset)
(Long.MIN_VALUE + 1) ^ Long.MIN_VALUE
is00..01
(Long.MIN_VALUE + 2) ^ Long.MIN_VALUE
is00..10
(Long.MIN_VALUE + 3) ^ Long.MIN_VALUE
is00..11
and so on until:
Long.MAX_VALUE ^ Long.MIN_VALUE
is11..11
(all 64 bits set)
The "flip" is done because Longs.compare()
needs input as unsigned [0, 264-1] values as per the method javadoc in your example:
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
add a comment |
Consider the bits that make up a long
type. Performing ^ Long.MIN_VALUE
converts a regular two's complement signed representation that holds [-263, 263-1] values into an unsigned representation that holds [0, 264-1] values.
You can see the process by taking the smallest long
value, adding one and "flipping" while inspecting the bits (e.g. with Long.toBinaryString()
):
Long.MIN_VALUE ^ Long.MIN_VALUE
is00..00
(all 64 bits unset)
(Long.MIN_VALUE + 1) ^ Long.MIN_VALUE
is00..01
(Long.MIN_VALUE + 2) ^ Long.MIN_VALUE
is00..10
(Long.MIN_VALUE + 3) ^ Long.MIN_VALUE
is00..11
and so on until:
Long.MAX_VALUE ^ Long.MIN_VALUE
is11..11
(all 64 bits set)
The "flip" is done because Longs.compare()
needs input as unsigned [0, 264-1] values as per the method javadoc in your example:
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
Consider the bits that make up a long
type. Performing ^ Long.MIN_VALUE
converts a regular two's complement signed representation that holds [-263, 263-1] values into an unsigned representation that holds [0, 264-1] values.
You can see the process by taking the smallest long
value, adding one and "flipping" while inspecting the bits (e.g. with Long.toBinaryString()
):
Long.MIN_VALUE ^ Long.MIN_VALUE
is00..00
(all 64 bits unset)
(Long.MIN_VALUE + 1) ^ Long.MIN_VALUE
is00..01
(Long.MIN_VALUE + 2) ^ Long.MIN_VALUE
is00..10
(Long.MIN_VALUE + 3) ^ Long.MIN_VALUE
is00..11
and so on until:
Long.MAX_VALUE ^ Long.MIN_VALUE
is11..11
(all 64 bits set)
The "flip" is done because Longs.compare()
needs input as unsigned [0, 264-1] values as per the method javadoc in your example:
/**
* Compares the two specified {@code long} values, treating them as unsigned values between
* {@code 0} and {@code 2^64 - 1} inclusive.
*
edited Nov 23 at 10:22
answered Nov 22 at 23:06
Karol Dowbecki
15.7k82849
15.7k82849
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53438534%2fguavas-unsignedlong-why-does-it-xor-long-min-value%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown