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 }