UInt96.java
- /*
- * 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 96-bit unsigned integer.
- *
- * <p>This is a specialised class to implement an accumulator of {@code long} values
- * generated by squaring {@code int} values from an array (max observations=2^31).
- *
- * @since 1.1
- */
- final class UInt96 {
- /** Mask for the lower 32-bits of a long. */
- private static final long MASK32 = 0xffff_ffffL;
- // Low data is stored using an integer to allow efficient sum-with-carry addition
- /** bits 32-1 (low 32-bits). */
- private int c;
- /** bits 96-33. */
- private long ab;
- /**
- * Create an instance.
- */
- private UInt96() {
- // No-op
- }
- /**
- * Create an instance.
- *
- * @param x Value.
- */
- private UInt96(long x) {
- c = (int) x;
- ab = (int) (x >>> Integer.SIZE);
- }
- /**
- * Create an instance using a direct binary representation.
- * This is package-private for testing.
- *
- * @param hi High 64-bits.
- * @param lo Low 32-bits.
- */
- UInt96(long hi, int lo) {
- this.c = lo;
- this.ab = hi;
- }
- /**
- * Create an instance. The initial value is zero.
- *
- * @return the instance
- */
- static UInt96 create() {
- return new UInt96();
- }
- /**
- * Create an instance of the {@code long} value.
- * The value is assumed to be an unsigned 64-bit integer.
- *
- * @param x Value (must be positive).
- * @return the instance
- */
- static UInt96 of(long x) {
- return new UInt96(x);
- }
- /**
- * Adds the value. 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.
- final long s = x + (c & MASK32);
- c = (int) s;
- ab += s >>> Integer.SIZE;
- }
- /**
- * Adds the value.
- *
- * @param x Value.
- */
- void add(UInt96 x) {
- // Avoid issues adding to itself
- final int cc = x.c;
- final long aabb = x.ab;
- // Sum with carry.
- final long s = (cc & MASK32) + (c & MASK32);
- c = (int) s;
- ab += (s >>> Integer.SIZE) + aabb;
- }
- /**
- * Convert to a BigInteger.
- *
- * @return the value
- */
- BigInteger toBigInteger() {
- if (ab != 0) {
- final ByteBuffer bb = ByteBuffer.allocate(Integer.BYTES * 3)
- .putLong(ab)
- .putInt(c);
- return new BigInteger(1, bb.array());
- }
- return BigInteger.valueOf(c & MASK32);
- }
- /**
- * Return the lower 32-bits as an {@code int} value.
- *
- * @return bits 32-1
- */
- int lo32() {
- return c;
- }
- /**
- * Return the higher 64-bits as a {@code long} value.
- *
- * @return bits 96-33
- */
- long hi64() {
- return ab;
- }
- }