View Javadoc
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.examples.jmh.descriptive;
18  
19  import java.math.BigInteger;
20  import java.nio.ByteBuffer;
21  import org.apache.commons.numbers.core.DD;
22  
23  /**
24   * A 96-bit unsigned integer.
25   *
26   * <p>This is a copy of {@code o.a.c.statistics.descriptive.Int96} to allow benchmarking.
27   * Additional methods may have been added for comparative benchmarks.
28   *
29   * <p>This is a specialised class to implement an accumulator of {@code long} values
30   * generated by squaring {@code int} values from an array (max observations=2^31).
31   *
32   * @since 1.1
33   */
34  final class UInt96 {
35      /** Mask for the lower 32-bits of a long. */
36      private static final long MASK32 = 0xffff_ffffL;
37  
38      // Low data is stored using an integer to allow efficient sum-with-carry addition
39  
40      /** bits 32-1 (low 32-bits). */
41      private int c;
42      /** bits 96-33. */
43      private long ab;
44  
45      /**
46       * Create an instance.
47       */
48      private UInt96() {
49          // No-op
50      }
51  
52      /**
53       * Create an instance.
54       *
55       * @param x Value.
56       */
57      private UInt96(long x) {
58          c = (int) x;
59          ab = (int) (x >>> Integer.SIZE);
60      }
61  
62      /**
63       * Create an instance using a direct binary representation.
64       * This is package-private for testing.
65       *
66       * @param hi High 64-bits.
67       * @param lo Low 32-bits.
68       */
69      UInt96(long hi, int lo) {
70          this.c = lo;
71          this.ab = hi;
72      }
73  
74      /**
75       * Create an instance. The initial value is zero.
76       *
77       * @return the instance
78       */
79      static UInt96 create() {
80          return new UInt96();
81      }
82  
83      /**
84       * Create an instance of the {@code long} value.
85       * The value is assumed to be an unsigned 64-bit integer.
86       *
87       * @param x Value (must be positive).
88       * @return the instance
89       */
90      static UInt96 of(long x) {
91          return new UInt96(x);
92      }
93  
94      /**
95       * Adds the value. It is assumed to be positive, for example the square of an
96       * {@code int} value. However no check is performed for a negative value.
97       *
98       * <p>Note: This addition handles {@value Long#MIN_VALUE} as an unsigned
99       * value of 2^63.
100      *
101      * @param x Value.
102      */
103     void addPositive(long x) {
104         // Sum with carry.
105         // Assuming x is positive then x + lo will not overflow 64-bits
106         // so we do not have to split x into upper and lower 32-bit values.
107         final long s = x + (c & MASK32);
108         c = (int) s;
109         ab += s >>> Integer.SIZE;
110     }
111 
112     /**
113      * Adds the value.
114      *
115      * @param x Value.
116      */
117     void add(UInt96 x) {
118         // Avoid issues adding to itself
119         final int cc = x.c;
120         final long aabb = x.ab;
121         // Sum with carry.
122         final long s = (cc & MASK32) + (c & MASK32);
123         c = (int) s;
124         ab += (s >>> Integer.SIZE) + aabb;
125     }
126 
127     /**
128      * Convert to a BigInteger.
129      *
130      * @return the value
131      */
132     BigInteger toBigInteger() {
133         if (ab != 0) {
134             final ByteBuffer bb = ByteBuffer.allocate(Integer.BYTES * 3)
135                 .putLong(ab)
136                 .putInt(c);
137             return new BigInteger(1, bb.array());
138         }
139         return BigInteger.valueOf(c & MASK32);
140     }
141 
142     /**
143      * Convert to a double-double.
144      *
145      * @return the value
146      */
147     DD toDD() {
148         // Sum low to high
149         return DD.ofSum(c & MASK32, (ab & MASK32) * 0x1.0p32)
150             .add((ab >>> Integer.SIZE) * 0x1.0p64);
151     }
152 
153     /**
154      * Return the lower 32-bits as an {@code int} value.
155      *
156      * @return bits 32-1
157      */
158     int lo32() {
159         return c;
160     }
161 
162     /**
163      * Return the higher 64-bits as a {@code long} value.
164      *
165      * @return bits 96-33
166      */
167     long hi64() {
168         return ab;
169     }
170 }