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

org.apache.commons.statistics.descriptive.UInt192 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 192-bit unsigned integer.
 *
 * 

This is a specialised class to implement an accumulator of squared {@code long} values. * * @since 1.1 */ final class UInt192 { /** 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 f; /** bits 64-33. */ private int e; /** bits 96-65. */ private int d; /** bits 128-97. */ private int c; /** bits 192-129 (high 64-bits). */ private long ab; /** * Create an instance. */ private UInt192() { // No-op } /** * Create an instance using a direct binary representation. * This is package-private for testing. * * @param hi High 64-bits. * @param mid Middle 64-bits. * @param lo Low 64-bits. */ UInt192(long hi, long mid, long lo) { this.f = (int) lo; this.e = (int) (lo >>> Integer.SIZE); this.d = (int) mid; this.c = (int) (mid >>> Integer.SIZE); this.ab = hi; } /** * Create an instance using a direct binary representation. * * @param ab bits 192-129 (high 64-bits). * @param c bits 128-97. * @param d bits 96-65. * @param e bits 64-33. * @param f bits 32-1. */ private UInt192(long ab, int c, int d, int e, int f) { this.ab = ab; this.c = c; this.d = d; this.e = e; this.f = f; } /** * Create an instance. The initial value is zero. * * @return the instance */ static UInt192 create() { return new UInt192(); } /** * Adds the squared value {@code x * x}. * * @param x Value. */ void addSquare(long x) { final long lo = x * x; final long hi = IntMath.squareHigh(x); // Sum with carry. long s = (lo & MASK32) + (f & MASK32); f = (int) s; s = (s >>> Integer.SIZE) + (lo >>> Integer.SIZE) + (e & MASK32); e = (int) s; s = (s >>> Integer.SIZE) + (hi & MASK32) + (d & MASK32); d = (int) s; s = (s >>> Integer.SIZE) + (hi >>> Integer.SIZE) + (c & MASK32); c = (int) s; ab += s >>> Integer.SIZE; } /** * Adds the value. * * @param x Value. */ void add(UInt192 x) { // Avoid issues adding to itself final int ff = x.f; final int ee = x.e; final int dd = x.d; final int cc = x.c; final long aabb = x.ab; // Sum with carry. long s = (ff & MASK32) + (f & MASK32); f = (int) s; s = (s >>> Integer.SIZE) + (ee & MASK32) + (e & MASK32); e = (int) s; s = (s >>> Integer.SIZE) + (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 */ UInt192 unsignedMultiply(int x) { final long xx = x & MASK32; // Multiply with carry. long product = xx * (f & MASK32); final int ff = (int) product; product = (product >>> Integer.SIZE) + xx * (e & MASK32); final int ee = (int) product; product = (product >>> Integer.SIZE) + 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 UInt192(aabb, cc, dd, ee, ff); } /** * Subtracts the value. * Any overflow bits (negative result) are lost. * * @param x Value. * @return the difference */ UInt192 subtract(UInt128 x) { // Difference with carry. // Subtract common part. long diff = (f & MASK32) - (x.lo32() & MASK32); final int ff = (int) diff; diff = (diff >> Integer.SIZE) + (e & MASK32) - (x.mid32() & MASK32); final int ee = (int) diff; diff = (diff >> Integer.SIZE) + (d & MASK32) - (x.hi64() & MASK32); final int dd = (int) diff; diff = (diff >> Integer.SIZE) + (c & MASK32) - (x.hi64() >>> Integer.SIZE); 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; return new UInt192(aabb, cc, dd, ee, ff); } /** * Convert to a BigInteger. * * @return the value */ BigInteger toBigInteger() { final ByteBuffer bb = ByteBuffer.allocate(Integer.BYTES * 6) .putLong(ab) .putInt(c) .putInt(d) .putInt(e) .putInt(f); // Sign is always positive. This works for zero. return new BigInteger(1, bb.array()); } /** * Convert to a double. * * @return the value */ double toDouble() { final long h = hi64(); final long m = mid64(); final long l = lo64(); if (h == 0) { return IntMath.uint128ToDouble(m, l); } // For correct rounding we use a sticky bit to represent magnitude // lost from the low 64-bits. The result is scaled by 2^64. return IntMath.uint128ToDouble(h, m | ((l == 0) ? 0 : 1)) * 0x1.0p64; } /** * 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 | c | d) != 0 || e < 0) { throw new ArithmeticException("long integer overflow"); } return lo64(); } /** * Return the lower 64-bits as a {@code long} value. * * @return the low 64-bits */ long lo64() { return (f & MASK32) | ((e & MASK32) << Integer.SIZE); } /** * Return the middle 64-bits as a {@code long} value. * * @return bits 128-65 */ long mid64() { return (d & MASK32) | ((c & MASK32) << Integer.SIZE); } /** * Return the higher 64-bits as a {@code long} value. * * @return bits 192-129 */ long hi64() { return ab; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy