| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.statistics.descriptive; |
| |
| import java.math.BigInteger; |
| import java.nio.ByteBuffer; |
| |
| /** |
| * A mutable 128-bit unsigned integer. |
| * |
| * <p>This is a specialised class to implement an accumulator of {@code long} values |
| * generated by squaring {@code int} values. |
| * |
| * @since 1.1 |
| */ |
| final class UInt128 { |
| /** Mask for the lower 32-bits of a long. */ |
| private static final long MASK32 = 0xffff_ffffL; |
| |
| // Data is stored using integers to allow efficient sum-with-carry addition |
| |
| /** bits 32-1 (low 32-bits). */ |
| private int d; |
| /** bits 64-33. */ |
| private int c; |
| /** bits 128-65. */ |
| private long ab; |
| |
| /** |
| * Create an instance. |
| */ |
| private UInt128() { |
| // No-op |
| } |
| |
| /** |
| * Create an instance using a direct binary representation. |
| * |
| * @param hi High 64-bits. |
| * @param mid Middle 32-bits. |
| * @param lo Low 32-bits. |
| */ |
| private UInt128(long hi, int mid, int lo) { |
| this.d = lo; |
| this.c = mid; |
| this.ab = hi; |
| } |
| |
| /** |
| * Create an instance using a direct binary representation. |
| * This is package-private for testing. |
| * |
| * @param hi High 64-bits. |
| * @param lo Low 64-bits. |
| */ |
| UInt128(long hi, long lo) { |
| this.d = (int) lo; |
| this.c = (int) (lo >>> Integer.SIZE); |
| this.ab = hi; |
| } |
| |
| /** |
| * Create an instance. The initial value is zero. |
| * |
| * @return the instance |
| */ |
| static UInt128 create() { |
| return new UInt128(); |
| } |
| |
| /** |
| * Create an instance of the {@code UInt96} value. |
| * |
| * @param x Value. |
| * @return the instance |
| */ |
| static UInt128 of(UInt96 x) { |
| final int lo = x.lo32(); |
| final long hi = x.hi64(); |
| final UInt128 y = new UInt128(); |
| y.d = lo; |
| y.c = (int) hi; |
| y.ab = hi >>> Integer.SIZE; |
| return y; |
| } |
| |
| /** |
| * Adds the value in place. It is assumed to be positive, for example the square of an |
| * {@code int} value. However no check is performed for a negative value. |
| * |
| * <p>Note: This addition handles {@value Long#MIN_VALUE} as an unsigned |
| * value of 2^63. |
| * |
| * @param x Value. |
| */ |
| void addPositive(long x) { |
| // Sum with carry. |
| // Assuming x is positive then x + lo will not overflow 64-bits |
| // so we do not have to split x into upper and lower 32-bit values. |
| long s = x + (d & MASK32); |
| d = (int) s; |
| s = (s >>> Integer.SIZE) + (c & MASK32); |
| c = (int) s; |
| ab += s >>> Integer.SIZE; |
| } |
| |
| /** |
| * Adds the value in-place. |
| * |
| * @param x Value. |
| */ |
| void add(UInt128 x) { |
| // Avoid issues adding to itself |
| final int dd = x.d; |
| final int cc = x.c; |
| final long aabb = x.ab; |
| // Sum with carry. |
| long s = (dd & MASK32) + (d & MASK32); |
| d = (int) s; |
| s = (s >>> Integer.SIZE) + (cc & MASK32) + (c & MASK32); |
| c = (int) s; |
| ab += (s >>> Integer.SIZE) + aabb; |
| } |
| |
| /** |
| * Multiply by the unsigned value. |
| * Any overflow bits are lost. |
| * |
| * @param x Value. |
| * @return the product |
| */ |
| UInt128 unsignedMultiply(int x) { |
| final long xx = x & MASK32; |
| // Multiply with carry. |
| long product = xx * (d & MASK32); |
| final int dd = (int) product; |
| product = (product >>> Integer.SIZE) + xx * (c & MASK32); |
| final int cc = (int) product; |
| // Possible overflow here and bits are lost |
| final long aabb = (product >>> Integer.SIZE) + xx * ab; |
| return new UInt128(aabb, cc, dd); |
| } |
| |
| /** |
| * Subtracts the value. |
| * Any overflow bits (negative result) are lost. |
| * |
| * @param x Value. |
| * @return the difference |
| */ |
| UInt128 subtract(UInt128 x) { |
| // Difference with carry. |
| long diff = (d & MASK32) - (x.d & MASK32); |
| final int dd = (int) diff; |
| diff = (diff >> Integer.SIZE) + (c & MASK32) - (x.c & MASK32); |
| final int cc = (int) diff; |
| // Possible overflow here and bits are lost containing info on the |
| // magnitude of the true negative value |
| final long aabb = (diff >> Integer.SIZE) + ab - x.ab; |
| return new UInt128(aabb, cc, dd); |
| } |
| |
| /** |
| * Convert to a BigInteger. |
| * |
| * @return the value |
| */ |
| BigInteger toBigInteger() { |
| // Test if we have more than 63-bits |
| if (ab != 0 || c < 0) { |
| return new BigInteger(1, ByteBuffer.allocate(Integer.BYTES * 4) |
| .putLong(ab) |
| .putInt(c) |
| .putInt(d).array()); |
| } |
| // Create from a long |
| return BigInteger.valueOf(lo64()); |
| } |
| |
| /** |
| * Convert to a {@code double}. |
| * |
| * @return the value |
| */ |
| double toDouble() { |
| return IntMath.uint128ToDouble(hi64(), lo64()); |
| } |
| |
| /** |
| * Convert to an {@code int}; throwing an exception if the value overflows an {@code int}. |
| * |
| * @return the value |
| * @throws ArithmeticException if the value overflows an {@code int}. |
| * @see Math#toIntExact(long) |
| */ |
| int toIntExact() { |
| return Math.toIntExact(toLongExact()); |
| } |
| |
| /** |
| * Convert to a {@code long}; throwing an exception if the value overflows a {@code long}. |
| * |
| * @return the value |
| * @throws ArithmeticException if the value overflows a {@code long}. |
| */ |
| long toLongExact() { |
| // Test if we have more than 63-bits |
| if (ab != 0 || c < 0) { |
| throw new ArithmeticException("long integer overflow"); |
| } |
| return lo64(); |
| } |
| |
| /** |
| * Return the lower 64-bits as a {@code long} value. |
| * |
| * @return bits 64-1 |
| */ |
| long lo64() { |
| return (d & MASK32) | ((c & MASK32) << Integer.SIZE); |
| } |
| |
| /** |
| * Return the low 32-bits as an {@code int} value. |
| * |
| * @return bits 32-1 |
| */ |
| int lo32() { |
| return d; |
| } |
| |
| /** |
| * Return the middle 32-bits as an {@code int} value. |
| * |
| * @return bits 64-33 |
| */ |
| int mid32() { |
| return c; |
| } |
| |
| /** |
| * Return the higher 64-bits as a {@code long} value. |
| * |
| * @return bits 128-65 |
| */ |
| long hi64() { |
| return ab; |
| } |
| } |