UInt128.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. /**
  21.  * A mutable 128-bit unsigned integer.
  22.  *
  23.  * <p>This is a specialised class to implement an accumulator of {@code long} values
  24.  * generated by squaring {@code int} values.
  25.  *
  26.  * @since 1.1
  27.  */
  28. final class UInt128 {
  29.     /** Mask for the lower 32-bits of a long. */
  30.     private static final long MASK32 = 0xffff_ffffL;

  31.     // Data is stored using integers to allow efficient sum-with-carry addition

  32.     /** bits 32-1 (low 32-bits). */
  33.     private int d;
  34.     /** bits 64-33. */
  35.     private int c;
  36.     /** bits 128-65. */
  37.     private long ab;

  38.     /**
  39.      * Create an instance.
  40.      */
  41.     private UInt128() {
  42.         // No-op
  43.     }

  44.     /**
  45.      * Create an instance using a direct binary representation.
  46.      *
  47.      * @param hi High 64-bits.
  48.      * @param mid Middle 32-bits.
  49.      * @param lo Low 32-bits.
  50.      */
  51.     private UInt128(long hi, int mid, int lo) {
  52.         this.d = lo;
  53.         this.c = mid;
  54.         this.ab = hi;
  55.     }

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

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

  76.     /**
  77.      * Create an instance of the {@code UInt96} value.
  78.      *
  79.      * @param x Value.
  80.      * @return the instance
  81.      */
  82.     static UInt128 of(UInt96 x) {
  83.         final int lo = x.lo32();
  84.         final long hi = x.hi64();
  85.         final UInt128 y = new UInt128();
  86.         y.d = lo;
  87.         y.c = (int) hi;
  88.         y.ab = hi >>> Integer.SIZE;
  89.         return y;
  90.     }

  91.     /**
  92.      * Adds the value in place. It is assumed to be positive, for example the square of an
  93.      * {@code int} value. However no check is performed for a negative value.
  94.      *
  95.      * <p>Note: This addition handles {@value Long#MIN_VALUE} as an unsigned
  96.      * value of 2^63.
  97.      *
  98.      * @param x Value.
  99.      */
  100.     void addPositive(long x) {
  101.         // Sum with carry.
  102.         // Assuming x is positive then x + lo will not overflow 64-bits
  103.         // so we do not have to split x into upper and lower 32-bit values.
  104.         long s = x + (d & MASK32);
  105.         d = (int) s;
  106.         s = (s >>> Integer.SIZE) + (c & MASK32);
  107.         c = (int) s;
  108.         ab += s >>> Integer.SIZE;
  109.     }

  110.     /**
  111.      * Adds the value in-place.
  112.      *
  113.      * @param x Value.
  114.      */
  115.     void add(UInt128 x) {
  116.         // Avoid issues adding to itself
  117.         final int dd = x.d;
  118.         final int cc = x.c;
  119.         final long aabb = x.ab;
  120.         // Sum with carry.
  121.         long s = (dd & MASK32) + (d & MASK32);
  122.         d = (int) s;
  123.         s = (s >>> Integer.SIZE) + (cc & MASK32) + (c & MASK32);
  124.         c = (int) s;
  125.         ab += (s >>> Integer.SIZE) + aabb;
  126.     }

  127.     /**
  128.      * Multiply by the unsigned value.
  129.      * Any overflow bits are lost.
  130.      *
  131.      * @param x Value.
  132.      * @return the product
  133.      */
  134.     UInt128 unsignedMultiply(int x) {
  135.         final long xx = x & MASK32;
  136.         // Multiply with carry.
  137.         long product = xx * (d & MASK32);
  138.         final int dd = (int) product;
  139.         product = (product >>> Integer.SIZE) + xx * (c & MASK32);
  140.         final int cc = (int) product;
  141.         // Possible overflow here and bits are lost
  142.         final long aabb = (product >>> Integer.SIZE) + xx * ab;
  143.         return new UInt128(aabb, cc, dd);
  144.     }

  145.     /**
  146.      * Subtracts the value.
  147.      * Any overflow bits (negative result) are lost.
  148.      *
  149.      * @param x Value.
  150.      * @return the difference
  151.      */
  152.     UInt128 subtract(UInt128 x) {
  153.         // Difference with carry.
  154.         long diff = (d & MASK32) - (x.d & MASK32);
  155.         final int dd = (int) diff;
  156.         diff = (diff >> Integer.SIZE) + (c & MASK32) - (x.c & MASK32);
  157.         final int cc = (int) diff;
  158.         // Possible overflow here and bits are lost containing info on the
  159.         // magnitude of the true negative value
  160.         final long aabb = (diff >> Integer.SIZE) + ab - x.ab;
  161.         return new UInt128(aabb, cc, dd);
  162.     }

  163.     /**
  164.      * Convert to a BigInteger.
  165.      *
  166.      * @return the value
  167.      */
  168.     BigInteger toBigInteger() {
  169.         // Test if we have more than 63-bits
  170.         if (ab != 0 || c < 0) {
  171.             return new BigInteger(1, ByteBuffer.allocate(Integer.BYTES * 4)
  172.                 .putLong(ab)
  173.                 .putInt(c)
  174.                 .putInt(d).array());
  175.         }
  176.         // Create from a long
  177.         return BigInteger.valueOf(lo64());
  178.     }

  179.     /**
  180.      * Convert to a {@code double}.
  181.      *
  182.      * @return the value
  183.      */
  184.     double toDouble() {
  185.         return IntMath.uint128ToDouble(hi64(), lo64());
  186.     }

  187.     /**
  188.      * Convert to an {@code int}; throwing an exception if the value overflows an {@code int}.
  189.      *
  190.      * @return the value
  191.      * @throws ArithmeticException if the value overflows an {@code int}.
  192.      * @see Math#toIntExact(long)
  193.      */
  194.     int toIntExact() {
  195.         return Math.toIntExact(toLongExact());
  196.     }

  197.     /**
  198.      * Convert to a {@code long}; throwing an exception if the value overflows a {@code long}.
  199.      *
  200.      * @return the value
  201.      * @throws ArithmeticException if the value overflows a {@code long}.
  202.      */
  203.     long toLongExact() {
  204.         // Test if we have more than 63-bits
  205.         if (ab != 0 || c < 0) {
  206.             throw new ArithmeticException("long integer overflow");
  207.         }
  208.         return lo64();
  209.     }

  210.     /**
  211.      * Return the lower 64-bits as a {@code long} value.
  212.      *
  213.      * @return bits 64-1
  214.      */
  215.     long lo64() {
  216.         return (d & MASK32) | ((c & MASK32) << Integer.SIZE);
  217.     }

  218.     /**
  219.      * Return the low 32-bits as an {@code int} value.
  220.      *
  221.      * @return bits 32-1
  222.      */
  223.     int lo32() {
  224.         return d;
  225.     }

  226.     /**
  227.      * Return the middle 32-bits as an {@code int} value.
  228.      *
  229.      * @return bits 64-33
  230.      */
  231.     int mid32() {
  232.         return c;
  233.     }

  234.     /**
  235.      * Return the higher 64-bits as a {@code long} value.
  236.      *
  237.      * @return bits 128-65
  238.      */
  239.     long hi64() {
  240.         return ab;
  241.     }
  242. }