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.descriptive;
18  
19  import java.math.BigInteger;
20  import java.nio.ByteBuffer;
21  import org.apache.commons.numbers.core.DD;
22  
23  /**
24   * A mutable 128-bit signed integer.
25   *
26   * <p>This is a specialised class to implement an accumulator of {@code long} values.
27   *
28   * <p>Note: This number uses a signed long integer representation of:
29   *
30   * <pre>value = 2<sup>64</sup> * hi64 + lo64</pre>
31   *
32   * <p>If the high value is zero then the low value is the long representation of the
33   * number including the sign bit. Otherwise the low value corresponds to a correction
34   * term for the scaled high value which contains the sign-bit of the number.
35   *
36   * @since 1.1
37   */
38  final class Int128 {
39      /** Mask for the lower 32-bits of a long. */
40      private static final long MASK32 = 0xffff_ffffL;
41      /** 2^53. */
42      private static final long TWO_POW_53 = 1L << 53;
43  
44      /** low 64-bits. */
45      private long lo;
46      /** high 64-bits. */
47      private long hi;
48  
49      /**
50       * Create an instance.
51       */
52      private Int128() {
53          // No-op
54      }
55  
56      /**
57       * Create an instance.
58       *
59       * @param x Value.
60       */
61      private Int128(long x) {
62          lo = x;
63      }
64  
65      /**
66       * Create an instance using a direct binary representation.
67       * This is package-private for testing.
68       *
69       * @param hi High 64-bits.
70       * @param lo Low 64-bits.
71       */
72      Int128(long hi, long lo) {
73          this.lo = lo;
74          this.hi = hi;
75      }
76  
77      /**
78       * Create an instance. The initial value is zero.
79       *
80       * @return the instance
81       */
82      static Int128 create() {
83          return new Int128();
84      }
85  
86      /**
87       * Create an instance of the {@code long} value.
88       *
89       * @param x Value.
90       * @return the instance
91       */
92      static Int128 of(long x) {
93          return new Int128(x);
94      }
95  
96      /**
97       * Adds the value.
98       *
99       * @param x Value.
100      */
101     void add(long x) {
102         final long y = lo;
103         final long r = y + x;
104         // Overflow if the result has the opposite sign of both arguments
105         // (+,+) -> -
106         // (-,-) -> +
107         // Detect opposite sign:
108         if (((y ^ r) & (x ^ r)) < 0) {
109             // Carry overflow bit
110             hi += x < 0 ? -1 : 1;
111         }
112         lo = r;
113     }
114 
115     /**
116      * Adds the value.
117      *
118      * @param x Value.
119      */
120     void add(Int128 x) {
121         // Avoid issues adding to itself
122         final long l = x.lo;
123         final long h = x.hi;
124         add(l);
125         hi += h;
126     }
127 
128     /**
129      * Compute the square of the low 64-bits of this number.
130      *
131      * <p>Warning: This ignores the upper 64-bits. Use with caution.
132      *
133      * @return the square
134      */
135     UInt128 squareLow() {
136         final long x = lo;
137         final long upper = IntMath.squareHigh(x);
138         return new UInt128(upper, x * x);
139     }
140 
141     /**
142      * Convert to a BigInteger.
143      *
144      * @return the value
145      */
146     BigInteger toBigInteger() {
147         long h = hi;
148         long l = lo;
149         // Special cases
150         if (h == 0) {
151             return BigInteger.valueOf(l);
152         }
153         if (l == 0) {
154             return BigInteger.valueOf(h).shiftLeft(64);
155         }
156 
157         // The representation is 2^64 * hi64 + lo64.
158         // Here we avoid evaluating the addition:
159         // BigInteger.valueOf(l).add(BigInteger.valueOf(h).shiftLeft(64))
160         // It is faster to create from bytes.
161         // BigInteger bytes are an unsigned integer in BigEndian format, plus a sign.
162         // If both values are positive we can use the values unchanged.
163         // Otherwise selective negation is used to create a positive magnitude
164         // and we track the sign.
165         // Note: Negation of -2^63 is valid to create an unsigned 2^63.
166 
167         int sign = 1;
168         if ((h ^ l) < 0) {
169             // Opposite signs and lo64 is not zero.
170             // The lo64 bits are an adjustment to the magnitude of hi64
171             // to make it smaller.
172             // Here we rearrange to [2^64 * (hi64-1)] + [2^64 - lo64].
173             // The second term [2^64 - lo64] can use lo64 as an unsigned 64-bit integer.
174             // The first term [2^64 * (hi64-1)] does not work if low is zero.
175             // It would work if zero was detected and we carried the overflow
176             // bit up to h to make it equal to: (h - 1) + 1 == h.
177             // Instead lo64 == 0 is handled as a special case above.
178 
179             if (h >= 0) {
180                 // Treat (unchanged) low as an unsigned add
181                 h = h - 1;
182             } else {
183                 // As above with negation
184                 h = ~h; // -h - 1
185                 l = -l;
186                 sign = -1;
187             }
188         } else if (h < 0) {
189             // Invert negative values to create the equivalent positive magnitude.
190             h = -h;
191             l = -l;
192             sign = -1;
193         }
194 
195         return new BigInteger(sign,
196             ByteBuffer.allocate(Long.BYTES * 2)
197                 .putLong(h).putLong(l).array());
198     }
199 
200     /**
201      * Convert to a {@code double}.
202      *
203      * @return the value
204      */
205     double toDouble() {
206         long h = hi;
207         long l = lo;
208         // Special cases
209         if (h == 0) {
210             return l;
211         }
212         if (l == 0) {
213             return h * 0x1.0p64;
214         }
215         // Both h and l are non-zero and can be negated to a positive magnitude.
216         // Use the same logic as toBigInteger to create magnitude (h, l) and a sign.
217         int sign = 1;
218         if ((h ^ l) < 0) {
219             // Here we rearrange to [2^64 * (hi64-1)] + [2^64 - lo64].
220             if (h >= 0) {
221                 h = h - 1;
222             } else {
223                 // As above with negation
224                 h = ~h; // -h - 1
225                 l = -l;
226                 sign = -1;
227             }
228         } else if (h < 0) {
229             // Invert negative values to create the equivalent positive magnitude.
230             h = -h;
231             l = -l;
232             sign = -1;
233         }
234         final double x = IntMath.uint128ToDouble(h, l);
235         return sign < 0 ? -x : x;
236     }
237 
238     /**
239      * Convert to a double-double.
240      *
241      * @return the value
242      */
243     DD toDD() {
244         // Don't combine two 64-bit DD numbers:
245         // DD.of(hi).scalb(64).add(DD.of(lo))
246         // It is more accurate to create a 96-bit number and add the final 32-bits.
247         // Sum low to high.
248         // Note: Masking a negative hi number will create a small positive magnitude
249         // to add to a larger negative number:
250         // e.g. x = (x & 0xff) + ((x >> 8) << 8)
251         return DD.of(lo).add((hi & MASK32) * 0x1.0p64).add((hi >> Integer.SIZE) * 0x1.0p96);
252     }
253 
254     /**
255      * Divide by the count {@code n}, returning the value as a {@code double}.
256      *
257      * @param n Count.
258      * @return the quotient
259      */
260     double divideToDouble(long n) {
261         final DD a = toDD();
262         if (n < TWO_POW_53) {
263             // n is a representable double
264             return a.divide(n).doubleValue();
265         }
266         // Extended precision divide when n > 2^53
267         return a.divide(DD.of(n)).doubleValue();
268     }
269 
270     /**
271      * Convert to an {@code int}; throwing an exception if the value overflows an {@code int}.
272      *
273      * @return the value
274      * @throws ArithmeticException if the value overflows an {@code int}.
275      * @see Math#toIntExact(long)
276      */
277     int toIntExact() {
278         return Math.toIntExact(toLongExact());
279     }
280 
281     /**
282      * Convert to a {@code long}; throwing an exception if the value overflows a {@code long}.
283      *
284      * @return the value
285      * @throws ArithmeticException if the value overflows a {@code long}.
286      */
287     long toLongExact() {
288         if (hi != 0) {
289             throw new ArithmeticException("long integer overflow");
290         }
291         return lo;
292     }
293 
294     /**
295      * Return the lower 64-bits as a {@code long} value.
296      *
297      * <p>If the high value is zero then the low value is the long representation of the
298      * number including the sign bit. Otherwise this value corresponds to a correction
299      * term for the scaled high value which contains the sign-bit of the number
300      * (see {@link Int128}).
301      *
302      * @return the low 64-bits
303      */
304     long lo64() {
305         return lo;
306     }
307 
308     /**
309      * Return the higher 64-bits as a {@code long} value.
310      *
311      * @return the high 64-bits
312      * @see #lo64()
313      */
314     long hi64() {
315         return hi;
316     }
317 }