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 128-bit unsigned integer. 25 * 26 * <p>This is a copy of {@code o.a.c.statistics.descriptive.UInt128} 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. 31 * 32 * @since 1.1 33 */ 34 final class UInt128 { 35 /** Mask for the lower 32-bits of a long. */ 36 private static final long MASK32 = 0xffff_ffffL; 37 38 // Data is stored using integers to allow efficient sum-with-carry addition 39 40 /** low 32-bits. */ 41 private int d; 42 /** low 32-bits. */ 43 private int c; 44 /** high 64-bits. */ 45 private long ab; 46 47 /** 48 * Create an instance. 49 */ 50 private UInt128() { 51 // No-op 52 } 53 54 /** 55 * Create an instance. 56 * 57 * @param x Value. 58 */ 59 private UInt128(long x) { 60 d = (int) x; 61 c = (int) (x >>> Integer.SIZE); 62 } 63 64 /** 65 * Create an instance using a direct binary representation. 66 * 67 * @param hi High 64-bits. 68 * @param mid Middle 32-bits. 69 * @param lo Low 32-bits. 70 */ 71 private UInt128(long hi, int mid, int lo) { 72 this.d = lo; 73 this.c = mid; 74 this.ab = hi; 75 } 76 77 /** 78 * Create an instance using a direct binary representation. 79 * This is package-private for testing. 80 * 81 * @param hi High 64-bits. 82 * @param lo Low 64-bits. 83 */ 84 UInt128(long hi, long lo) { 85 this.d = (int) lo; 86 this.c = (int) (lo >>> Integer.SIZE); 87 this.ab = hi; 88 } 89 90 /** 91 * Create an instance. The initial value is zero. 92 * 93 * @return the instance 94 */ 95 static UInt128 create() { 96 return new UInt128(); 97 } 98 99 /** 100 * Create an instance of the {@code long} value. 101 * The value is assumed to be an unsigned 64-bit integer. 102 * 103 * @param x Value (must be positive). 104 * @return the instance 105 */ 106 static UInt128 of(long x) { 107 return new UInt128(x); 108 } 109 110 /** 111 * Create an instance of the {@code UInt96} value. 112 * 113 * @param x Value. 114 * @return the instance 115 */ 116 static UInt128 of(UInt96 x) { 117 final int lo = x.lo32(); 118 final long hi = x.hi64(); 119 final UInt128 y = new UInt128(); 120 y.d = lo; 121 y.c = (int) hi; 122 y.ab = hi >>> Integer.SIZE; 123 return y; 124 } 125 126 /** 127 * Adds the value in place. It is assumed to be positive, for example the square of an 128 * {@code int} value. However no check is performed for a negative value. 129 * 130 * <p>Note: This addition handles {@value Long#MIN_VALUE} as an unsigned 131 * value of 2^63. 132 * 133 * @param x Value. 134 */ 135 void addPositive(long x) { 136 // Sum with carry. 137 // Assuming x is positive then x + lo will not overflow 64-bits 138 // so we do not have to split x into upper and lower 32-bit values. 139 long s = x + (d & MASK32); 140 d = (int) s; 141 s = (s >>> Integer.SIZE) + (c & MASK32); 142 c = (int) s; 143 ab += s >>> Integer.SIZE; 144 } 145 146 /** 147 * Adds the value in-place. 148 * 149 * @param x Value. 150 */ 151 void add(UInt128 x) { 152 // Avoid issues adding to itself 153 final int dd = x.d; 154 final int cc = x.c; 155 final long aabb = x.ab; 156 // Sum with carry. 157 long s = (dd & MASK32) + (d & MASK32); 158 d = (int) s; 159 s = (s >>> Integer.SIZE) + (cc & MASK32) + (c & MASK32); 160 c = (int) s; 161 ab += (s >>> Integer.SIZE) + aabb; 162 } 163 164 /** 165 * Multiply by the unsigned value. 166 * Any overflow bits are lost. 167 * 168 * @param x Value. 169 * @return the product 170 */ 171 UInt128 unsignedMultiply(int x) { 172 final long xx = x & MASK32; 173 // Multiply with carry. 174 long product = xx * (d & MASK32); 175 final int dd = (int) product; 176 product = (product >>> Integer.SIZE) + xx * (c & MASK32); 177 final int cc = (int) product; 178 // Possible overflow here and bits are lost 179 final long aabb = (product >>> Integer.SIZE) + xx * ab; 180 return new UInt128(aabb, cc, dd); 181 } 182 183 /** 184 * Subtracts the value. 185 * Any overflow bits (negative result) are lost. 186 * 187 * @param x Value. 188 * @return the difference 189 */ 190 UInt128 subtract(UInt128 x) { 191 // Difference with carry. 192 long diff = (d & MASK32) - (x.d & MASK32); 193 final int dd = (int) diff; 194 diff = (diff >> Integer.SIZE) + (c & MASK32) - (x.c & MASK32); 195 final int cc = (int) diff; 196 // Possible overflow here and bits are lost containing info on the 197 // magnitude of the true negative value 198 final long aabb = (diff >> Integer.SIZE) + ab - x.ab; 199 return new UInt128(aabb, cc, dd); 200 } 201 202 /** 203 * Convert to a BigInteger. 204 * 205 * @return the value 206 */ 207 BigInteger toBigInteger() { 208 // Test if we have more than 63-bits 209 if (ab != 0 || c < 0) { 210 final ByteBuffer bb = ByteBuffer.allocate(Integer.BYTES * 4) 211 .putLong(ab) 212 .putInt(c) 213 .putInt(d); 214 return new BigInteger(1, bb.array()); 215 } 216 // Create from a long 217 return BigInteger.valueOf(((c & MASK32) << Integer.SIZE) | (d & MASK32)); 218 } 219 220 /** 221 * Convert to a double-double. 222 * 223 * @return the value 224 */ 225 DD toDD() { 226 // Sum low to high 227 return DD.ofSum(d & MASK32, (c & MASK32) * 0x1.0p32) 228 .add((ab & MASK32) * 0x1.0p64) 229 .add((ab >>> Integer.SIZE) * 0x1.0p96); 230 } 231 232 /** 233 * Convert to a {@code double}. 234 * 235 * @return the value 236 */ 237 double toDouble() { 238 return IntMath.uin128ToDouble(hi64(), lo64()); 239 } 240 241 /** 242 * Return the lower 64-bits as a {@code long} value. 243 * 244 * @return the low 64-bits 245 */ 246 long lo64() { 247 return (d & MASK32) | ((c & MASK32) << Integer.SIZE); 248 } 249 250 /** 251 * Return the low 32-bits as an {@code int} value. 252 * 253 * @return bits 32-1 254 */ 255 int lo32() { 256 return d; 257 } 258 259 /** 260 * Return the middle 32-bits as an {@code int} value. 261 * 262 * @return bits 64-33 263 */ 264 int mid32() { 265 return c; 266 } 267 268 /** 269 * Return the higher 64-bits as a {@code long} value. 270 * 271 * @return bits 128-65 272 */ 273 long hi64() { 274 return ab; 275 } 276 277 /** 278 * Return the higher 32-bits as an {@code int} value. 279 * 280 * @return bits 128-97 281 */ 282 int hi32() { 283 return (int) (ab >>> Integer.SIZE); 284 } 285 }