Int128.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  * contributor license agreements.  See the NOTICE file distributed with
  4.  * this work for additional information regarding copyright ownership.
  5.  * The ASF licenses this file to You under the Apache License, Version 2.0
  6.  * (the "License"); you may not use this file except in compliance with
  7.  * the License.  You may obtain a copy of the License at
  8.  *
  9.  *      http://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  * Unless required by applicable law or agreed to in writing, software
  12.  * distributed under the License is distributed on an "AS IS" BASIS,
  13.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  * See the License for the specific language governing permissions and
  15.  * limitations under the License.
  16.  */
  17. package org.apache.commons.statistics.descriptive;

  18. import java.math.BigInteger;
  19. import java.nio.ByteBuffer;
  20. import org.apache.commons.numbers.core.DD;

  21. /**
  22.  * A mutable 128-bit signed integer.
  23.  *
  24.  * <p>This is a specialised class to implement an accumulator of {@code long} values.
  25.  *
  26.  * <p>Note: This number uses a signed long integer representation of:
  27.  *
  28.  * <pre>value = 2<sup>64</sup> * hi64 + lo64</pre>
  29.  *
  30.  * <p>If the high value is zero then the low value is the long representation of the
  31.  * number including the sign bit. Otherwise the low value corresponds to a correction
  32.  * term for the scaled high value which contains the sign-bit of the number.
  33.  *
  34.  * @since 1.1
  35.  */
  36. final class Int128 {
  37.     /** Mask for the lower 32-bits of a long. */
  38.     private static final long MASK32 = 0xffff_ffffL;

  39.     /** low 64-bits. */
  40.     private long lo;
  41.     /** high 64-bits. */
  42.     private long hi;

  43.     /**
  44.      * Create an instance.
  45.      */
  46.     private Int128() {
  47.         // No-op
  48.     }

  49.     /**
  50.      * Create an instance.
  51.      *
  52.      * @param x Value.
  53.      */
  54.     private Int128(long x) {
  55.         lo = x;
  56.     }

  57.     /**
  58.      * Create an instance using a direct binary representation.
  59.      * This is package-private for testing.
  60.      *
  61.      * @param hi High 64-bits.
  62.      * @param lo Low 64-bits.
  63.      */
  64.     Int128(long hi, long lo) {
  65.         this.lo = lo;
  66.         this.hi = hi;
  67.     }

  68.     /**
  69.      * Create an instance. The initial value is zero.
  70.      *
  71.      * @return the instance
  72.      */
  73.     static Int128 create() {
  74.         return new Int128();
  75.     }

  76.     /**
  77.      * Create an instance of the {@code long} value.
  78.      *
  79.      * @param x Value.
  80.      * @return the instance
  81.      */
  82.     static Int128 of(long x) {
  83.         return new Int128(x);
  84.     }

  85.     /**
  86.      * Adds the value.
  87.      *
  88.      * @param x Value.
  89.      */
  90.     void add(long x) {
  91.         final long y = lo;
  92.         final long r = y + x;
  93.         // Overflow if the result has the opposite sign of both arguments
  94.         // (+,+) -> -
  95.         // (-,-) -> +
  96.         // Detect opposite sign:
  97.         if (((y ^ r) & (x ^ r)) < 0) {
  98.             // Carry overflow bit
  99.             hi += x < 0 ? -1 : 1;
  100.         }
  101.         lo = r;
  102.     }

  103.     /**
  104.      * Adds the value.
  105.      *
  106.      * @param x Value.
  107.      */
  108.     void add(Int128 x) {
  109.         // Avoid issues adding to itself
  110.         final long l = x.lo;
  111.         final long h = x.hi;
  112.         add(l);
  113.         hi += h;
  114.     }

  115.     /**
  116.      * Compute the square of the low 64-bits of this number.
  117.      *
  118.      * <p>Warning: This ignores the upper 64-bits. Use with caution.
  119.      *
  120.      * @return the square
  121.      */
  122.     UInt128 squareLow() {
  123.         final long x = lo;
  124.         final long upper = IntMath.squareHigh(x);
  125.         return new UInt128(upper, x * x);
  126.     }

  127.     /**
  128.      * Convert to a BigInteger.
  129.      *
  130.      * @return the value
  131.      */
  132.     BigInteger toBigInteger() {
  133.         long h = hi;
  134.         long l = lo;
  135.         // Special cases
  136.         if (h == 0) {
  137.             return BigInteger.valueOf(l);
  138.         }
  139.         if (l == 0) {
  140.             return BigInteger.valueOf(h).shiftLeft(64);
  141.         }

  142.         // The representation is 2^64 * hi64 + lo64.
  143.         // Here we avoid evaluating the addition:
  144.         // BigInteger.valueOf(l).add(BigInteger.valueOf(h).shiftLeft(64))
  145.         // It is faster to create from bytes.
  146.         // BigInteger bytes are an unsigned integer in BigEndian format, plus a sign.
  147.         // If both values are positive we can use the values unchanged.
  148.         // Otherwise selective negation is used to create a positive magnitude
  149.         // and we track the sign.
  150.         // Note: Negation of -2^63 is valid to create an unsigned 2^63.

  151.         int sign = 1;
  152.         if ((h ^ l) < 0) {
  153.             // Opposite signs and lo64 is not zero.
  154.             // The lo64 bits are an adjustment to the magnitude of hi64
  155.             // to make it smaller.
  156.             // Here we rearrange to [2^64 * (hi64-1)] + [2^64 - lo64].
  157.             // The second term [2^64 - lo64] can use lo64 as an unsigned 64-bit integer.
  158.             // The first term [2^64 * (hi64-1)] does not work if low is zero.
  159.             // It would work if zero was detected and we carried the overflow
  160.             // bit up to h to make it equal to: (h - 1) + 1 == h.
  161.             // Instead lo64 == 0 is handled as a special case above.

  162.             if (h >= 0) {
  163.                 // Treat (unchanged) low as an unsigned add
  164.                 h = h - 1;
  165.             } else {
  166.                 // As above with negation
  167.                 h = ~h; // -h - 1
  168.                 l = -l;
  169.                 sign = -1;
  170.             }
  171.         } else if (h < 0) {
  172.             // Invert negative values to create the equivalent positive magnitude.
  173.             h = -h;
  174.             l = -l;
  175.             sign = -1;
  176.         }

  177.         return new BigInteger(sign,
  178.             ByteBuffer.allocate(Long.BYTES * 2)
  179.                 .putLong(h).putLong(l).array());
  180.     }

  181.     /**
  182.      * Convert to a {@code double}.
  183.      *
  184.      * @return the value
  185.      */
  186.     double toDouble() {
  187.         long h = hi;
  188.         long l = lo;
  189.         // Special cases
  190.         if (h == 0) {
  191.             return l;
  192.         }
  193.         if (l == 0) {
  194.             return h * 0x1.0p64;
  195.         }
  196.         // Both h and l are non-zero and can be negated to a positive magnitude.
  197.         // Use the same logic as toBigInteger to create magnitude (h, l) and a sign.
  198.         int sign = 1;
  199.         if ((h ^ l) < 0) {
  200.             // Here we rearrange to [2^64 * (hi64-1)] + [2^64 - lo64].
  201.             if (h >= 0) {
  202.                 h = h - 1;
  203.             } else {
  204.                 // As above with negation
  205.                 h = ~h; // -h - 1
  206.                 l = -l;
  207.                 sign = -1;
  208.             }
  209.         } else if (h < 0) {
  210.             // Invert negative values to create the equivalent positive magnitude.
  211.             h = -h;
  212.             l = -l;
  213.             sign = -1;
  214.         }
  215.         final double x = IntMath.uint128ToDouble(h, l);
  216.         return sign < 0 ? -x : x;
  217.     }

  218.     /**
  219.      * Convert to a double-double.
  220.      *
  221.      * @return the value
  222.      */
  223.     DD toDD() {
  224.         // Don't combine two 64-bit DD numbers:
  225.         // DD.of(hi).scalb(64).add(DD.of(lo))
  226.         // It is more accurate to create a 96-bit number and add the final 32-bits.
  227.         // Sum low to high.
  228.         // Note: Masking a negative hi number will create a small positive magnitude
  229.         // to add to a larger negative number:
  230.         // e.g. x = (x & 0xff) + ((x >> 8) << 8)
  231.         return DD.of(lo).add((hi & MASK32) * 0x1.0p64).add((hi >> Integer.SIZE) * 0x1.0p96);
  232.     }

  233.     /**
  234.      * Convert to an {@code int}; throwing an exception if the value overflows an {@code int}.
  235.      *
  236.      * @return the value
  237.      * @throws ArithmeticException if the value overflows an {@code int}.
  238.      * @see Math#toIntExact(long)
  239.      */
  240.     int toIntExact() {
  241.         return Math.toIntExact(toLongExact());
  242.     }

  243.     /**
  244.      * Convert to a {@code long}; throwing an exception if the value overflows a {@code long}.
  245.      *
  246.      * @return the value
  247.      * @throws ArithmeticException if the value overflows a {@code long}.
  248.      */
  249.     long toLongExact() {
  250.         if (hi != 0) {
  251.             throw new ArithmeticException("long integer overflow");
  252.         }
  253.         return lo;
  254.     }

  255.     /**
  256.      * Return the lower 64-bits as a {@code long} value.
  257.      *
  258.      * <p>If the high value is zero then the low value is the long representation of the
  259.      * number including the sign bit. Otherwise this value corresponds to a correction
  260.      * term for the scaled high value which contains the sign-bit of the number
  261.      * (see {@link Int128}).
  262.      *
  263.      * @return the low 64-bits
  264.      */
  265.     long lo64() {
  266.         return lo;
  267.     }

  268.     /**
  269.      * Return the higher 64-bits as a {@code long} value.
  270.      *
  271.      * @return the high 64-bits
  272.      * @see #lo64()
  273.      */
  274.     long hi64() {
  275.         return hi;
  276.     }
  277. }