Guava's UnsignedLong: Why does it XOR Long.MIN_VALUE












6














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));
}









share|improve this question





























    6














    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));
    }









    share|improve this question



























      6












      6








      6







      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));
      }









      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 at 10:13









      Karol Dowbecki

      15.7k82849




      15.7k82849










      asked Nov 22 at 22:12









      Setheron

      1,47432244




      1,47432244
























          2 Answers
          2






          active

          oldest

          votes


















          1














          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.






          share|improve this answer





























            0














            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 is 00..00 (all 64 bits unset)


            • (Long.MIN_VALUE + 1) ^ Long.MIN_VALUE is 00..01


            • (Long.MIN_VALUE + 2) ^ Long.MIN_VALUE is 00..10


            • (Long.MIN_VALUE + 3) ^ Long.MIN_VALUE is 00..11


            and so on until:





            • Long.MAX_VALUE ^ Long.MIN_VALUE is 11..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.
            *





            share|improve this answer























              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
              });


              }
              });














              draft saved

              draft discarded


















              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









              1














              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.






              share|improve this answer


























                1














                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.






                share|improve this answer
























                  1












                  1








                  1






                  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.






                  share|improve this answer












                  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.







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Nov 23 at 2:34









                  harold

                  41.2k356108




                  41.2k356108

























                      0














                      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 is 00..00 (all 64 bits unset)


                      • (Long.MIN_VALUE + 1) ^ Long.MIN_VALUE is 00..01


                      • (Long.MIN_VALUE + 2) ^ Long.MIN_VALUE is 00..10


                      • (Long.MIN_VALUE + 3) ^ Long.MIN_VALUE is 00..11


                      and so on until:





                      • Long.MAX_VALUE ^ Long.MIN_VALUE is 11..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.
                      *





                      share|improve this answer




























                        0














                        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 is 00..00 (all 64 bits unset)


                        • (Long.MIN_VALUE + 1) ^ Long.MIN_VALUE is 00..01


                        • (Long.MIN_VALUE + 2) ^ Long.MIN_VALUE is 00..10


                        • (Long.MIN_VALUE + 3) ^ Long.MIN_VALUE is 00..11


                        and so on until:





                        • Long.MAX_VALUE ^ Long.MIN_VALUE is 11..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.
                        *





                        share|improve this answer


























                          0












                          0








                          0






                          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 is 00..00 (all 64 bits unset)


                          • (Long.MIN_VALUE + 1) ^ Long.MIN_VALUE is 00..01


                          • (Long.MIN_VALUE + 2) ^ Long.MIN_VALUE is 00..10


                          • (Long.MIN_VALUE + 3) ^ Long.MIN_VALUE is 00..11


                          and so on until:





                          • Long.MAX_VALUE ^ Long.MIN_VALUE is 11..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.
                          *





                          share|improve this answer














                          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 is 00..00 (all 64 bits unset)


                          • (Long.MIN_VALUE + 1) ^ Long.MIN_VALUE is 00..01


                          • (Long.MIN_VALUE + 2) ^ Long.MIN_VALUE is 00..10


                          • (Long.MIN_VALUE + 3) ^ Long.MIN_VALUE is 00..11


                          and so on until:





                          • Long.MAX_VALUE ^ Long.MIN_VALUE is 11..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.
                          *






                          share|improve this answer














                          share|improve this answer



                          share|improve this answer








                          edited Nov 23 at 10:22

























                          answered Nov 22 at 23:06









                          Karol Dowbecki

                          15.7k82849




                          15.7k82849






























                              draft saved

                              draft discarded




















































                              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.




                              draft saved


                              draft discarded














                              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





















































                              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







                              Popular posts from this blog

                              A CLEAN and SIMPLE way to add appendices to Table of Contents and bookmarks

                              Calculate evaluation metrics using cross_val_predict sklearn

                              Insert data from modal to MySQL (multiple modal on website)