All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.statistics.descriptive.UInt128 Maven / Gradle / Ivy

/*
 * 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.
 *
 * 

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. * *

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





© 2015 - 2024 Weber Informatics LLC | Privacy Policy