Skip to content

Commit f57f24e

Browse files
committed
rename class and methods
1 parent f7bf043 commit f57f24e

15 files changed

Lines changed: 170 additions & 171 deletions

src/main/java/de/tilman_neumann/jml/base/Uint128.java renamed to src/main/java/de/tilman_neumann/jml/base/Int128.java

Lines changed: 95 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,15 @@
2828
*
2929
* @author Tilman Neumann
3030
*/
31-
// TODO Now that there are signed methods, this class needs a refactoring
32-
public class Uint128 {
31+
public class Int128 {
3332
@SuppressWarnings("unused")
34-
private static final Logger LOG = LogManager.getLogger(Uint128.class);
33+
private static final Logger LOG = LogManager.getLogger(Int128.class);
3534

3635
private static final boolean DEBUG = false;
3736

3837
private long high, low;
3938

40-
public Uint128(long high, long low) {
39+
public Int128(long high, long low) {
4140
this.high = high;
4241
this.low = low;
4342
}
@@ -55,19 +54,19 @@ public long getLow() {
5554
* @param b
5655
* @return this + b
5756
*/
58-
public Uint128 add(Uint128 b) {
57+
public Int128 add(Int128 b) {
5958
long r_lo = low + b.getLow();
6059
long carry = Long.compareUnsigned(r_lo, low) < 0 ? 1 : 0;
6160
long r_hi = high + b.getHigh() + carry;
62-
return new Uint128(r_hi, r_lo);
61+
return new Int128(r_hi, r_lo);
6362
}
6463

6564
/**
6665
* Add two 128 bit integers, return the high part.
6766
* @param b
6867
* @return high part of this + b
6968
*/
70-
public long add_getHigh(Uint128 b) {
69+
public long add_getHigh(Int128 b) {
7170
long r_lo = low + b.getLow();
7271
long carry = Long.compareUnsigned(r_lo, low) < 0 ? 1 : 0;
7372
return high + b.getHigh() + carry;
@@ -79,14 +78,62 @@ public long add_getHigh(Uint128 b) {
7978
* @param b
8079
* @return this - b, may be negative
8180
*/
82-
public Uint128 subtract(Uint128 b) {
81+
public Int128 subtract(Int128 b) {
8382
long b_lo = b.getLow();
8483
long r_lo = low - b_lo;
8584
long borrow = Long.compareUnsigned(low, b_lo) < 0 ? 1 : 0;
8685
long r_hi = high - b.getHigh() - borrow;
87-
return new Uint128(r_hi, r_lo);
86+
return new Int128(r_hi, r_lo);
8887
}
8988

89+
/**
90+
* Multiplication of two signed 64 bit integers, adapted from Henry S. Warren, Hacker's Delight, Addison-Wesley, 2nd edition, chapter 8-2.
91+
* This is more or less what Java9 does in Math.multiplyHigh(), but I think I made it a bit faster optimizing register usage.
92+
*
93+
* @param a signed long
94+
* @param b signed long
95+
* @return a*b as a signed 127 bit number
96+
*/
97+
public static Int128 mul64(long a, long b) {
98+
final long a_hi = a >> 32;
99+
final long a_lo = a & 0xFFFFFFFFL;
100+
final long b_hi = b >> 32;
101+
final long b_lo = b & 0xFFFFFFFFL;
102+
103+
// use b_lo twice as first argument hoping that this optimizes register usage
104+
final long w0 = b_lo * a_lo;
105+
final long t = b_lo * a_hi + (w0 >>> 32);
106+
// same with t
107+
final long w2 = t >> 32;
108+
final long w1 = (t & 0xFFFFFFFFL) + a_lo * b_hi;
109+
110+
final long r_hi = a_hi * b_hi + w2 + (w1 >> 32);
111+
final long r_lo = a * b;
112+
return new Int128(r_hi, r_lo);
113+
}
114+
115+
/**
116+
* Multiplication of two signed 64-bit integers using Math.multiplyHigh().
117+
* Pretty fast if supported by intrinsics, which needs newer hardware and Java 10+.<br><br>
118+
*
119+
* @param a signed long
120+
* @param b signed long
121+
* @return a*b as a signed 127 bit number
122+
*/
123+
public static Int128 mul64MH(long a, long b) {
124+
final long r_lo = a*b;
125+
final long r_hi = Math.multiplyHigh(a, b);
126+
127+
if (DEBUG) {
128+
// compare to pure Java implementation
129+
Int128 testResult = mul64(a, b);
130+
Ensure.ensureEquals(testResult.high, r_hi);
131+
Ensure.ensureEquals(testResult.low, r_lo);
132+
}
133+
134+
return new Int128(r_hi, r_lo);
135+
}
136+
90137
/**
91138
* Multiplication of unsigned 63 bit integers,
92139
* following https://stackoverflow.com/questions/18859207/high-bits-of-long-multiplication-in-java.
@@ -98,7 +145,7 @@ public Uint128 subtract(Uint128 b) {
98145
* @param b
99146
* @return a*b accurate for inputs <= 63 bit
100147
*/
101-
public static Uint128 mul63(long a, long b) {
148+
public static Int128 mul63Unsigned(long a, long b) {
102149
final long a_hi = a >>> 32;
103150
final long b_hi = b >>> 32;
104151
final long a_lo = a & 0xFFFFFFFFL;
@@ -108,7 +155,7 @@ public static Uint128 mul63(long a, long b) {
108155
final long hi_prod = a_hi * b_hi;
109156
final long r_hi = (((lo_prod >>> 32) + med_term) >>> 32) + hi_prod;
110157
final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
111-
return new Uint128(r_hi, r_lo);
158+
return new Int128(r_hi, r_lo);
112159
}
113160

114161
/**
@@ -118,7 +165,7 @@ public static Uint128 mul63(long a, long b) {
118165
* @param b unsigned long
119166
* @return a*b
120167
*/
121-
public static Uint128 mul64(long a, long b) {
168+
public static Int128 mul64Unsigned(long a, long b) {
122169
final long a_hi = a >>> 32;
123170
final long b_hi = b >>> 32;
124171
final long a_lo = a & 0xFFFFFFFFL;
@@ -131,11 +178,11 @@ public static Uint128 mul64(long a, long b) {
131178
final long hi_prod = a_hi * b_hi;
132179

133180
// the medium term could overflow
134-
final long carry = (med_term+Long.MIN_VALUE < med_prod1+Long.MIN_VALUE) ? 1L<<32 : 0;
181+
final long carry = Long.compareUnsigned(med_term, med_prod1) < 0 ? 1L<<32 : 0;
135182
final long r_hi = (((lo_prod >>> 32) + med_term) >>> 32) + hi_prod + carry;
136183
final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
137184

138-
return new Uint128(r_hi, r_lo);
185+
return new Int128(r_hi, r_lo);
139186
}
140187

141188
/**
@@ -146,68 +193,20 @@ public static Uint128 mul64(long a, long b) {
146193
* @param b
147194
* @return
148195
*/
149-
public static Uint128 mul64_MH(long a, long b) {
196+
public static Int128 mul64UnsignedMH(long a, long b) {
150197
final long r_lo = a*b;
151198
long r_hi = Math.multiplyHigh(a, b);
152199
if (a<0) r_hi += b;
153200
if (b<0) r_hi += a;
154201

155202
if (DEBUG) {
156203
// compare to pure Java implementation
157-
Uint128 testResult = mul64(a, b);
158-
Ensure.ensureEquals(testResult.high, r_hi);
159-
Ensure.ensureEquals(testResult.low, r_lo);
160-
}
161-
162-
return new Uint128(r_hi, r_lo);
163-
}
164-
165-
/**
166-
* Multiplication of two signed 64 bit integers, adapted from Henry S. Warren, Hacker's Delight, Addison-Wesley, 2nd edition, chapter 8-2.
167-
* This is more or less what Java9 does in Math.multiplyHigh(), but I think I made it a bit faster optimizing register usage.
168-
*
169-
* @param a signed long
170-
* @param b signed long
171-
* @return a*b as a signed 127 bit number
172-
*/
173-
public static Uint128 mul64Signed(long a, long b) {
174-
final long a_hi = a >> 32;
175-
final long a_lo = a & 0xFFFFFFFFL;
176-
final long b_hi = b >> 32;
177-
final long b_lo = b & 0xFFFFFFFFL;
178-
179-
// use b_lo twice as first argument hoping that this optimizes register usage
180-
final long w0 = b_lo * a_lo;
181-
final long t = b_lo * a_hi + (w0 >>> 32);
182-
// same with t
183-
final long w2 = t >> 32;
184-
final long w1 = (t & 0xFFFFFFFFL) + a_lo * b_hi;
185-
186-
final long r_hi = a_hi * b_hi + w2 + (w1 >> 32);
187-
final long r_lo = a * b;
188-
return new Uint128(r_hi, r_lo);
189-
}
190-
191-
/**
192-
* Multiplication of two signed 64-bit integers using Math.multiplyHigh().
193-
* Pretty fast if supported by intrinsics, which needs newer hardware and Java 10+.<br><br>
194-
*
195-
* @param a signed long
196-
* @param b signed long
197-
* @return a*b as a signed 127 bit number
198-
*/
199-
public static Uint128 mul64SignedMH(long a, long b) {
200-
final long r_lo = a*b;
201-
final long r_hi = Math.multiplyHigh(a, b);
202-
203-
if (DEBUG) {
204-
// compare to pure Java implementation
205-
Uint128 testResult = mul64Signed(a, b);
204+
Int128 testResult = mul64Unsigned(a, b);
206205
Ensure.ensureEquals(testResult.high, r_hi);
207206
Ensure.ensureEquals(testResult.low, r_lo);
208207
}
209208

210-
return new Uint128(r_hi, r_lo);
209+
return new Int128(r_hi, r_lo);
211210
}
212211

213212
/**
@@ -217,7 +216,7 @@ public static Uint128 mul64SignedMH(long a, long b) {
217216
* @return a^2
218217
*/
219218
// XXX speed up using intrinsics like in mul64_MH() ?
220-
public static Uint128 square64(long a) {
219+
public static Int128 square64Unsigned(long a) {
221220
final long a_hi = a >>> 32;
222221
final long a_lo = a & 0xFFFFFFFFL;
223222

@@ -230,7 +229,7 @@ public static Uint128 square64(long a) {
230229
final long carry = (med_term+Long.MIN_VALUE < med_prod+Long.MIN_VALUE) ? 1L<<32 : 0;
231230
final long r_hi = (((lo_prod >>> 32) + med_term) >>> 32) + hi_prod + carry;
232231
final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
233-
return new Uint128(r_hi, r_lo);
232+
return new Int128(r_hi, r_lo);
234233
}
235234

236235
/**
@@ -240,34 +239,34 @@ public static Uint128 square64(long a) {
240239
* @param b Uint128
241240
* @return a*b as an array of [low, high] Uint128 objects;
242241
*/
243-
public static Uint128[] mul128/*_v2*/(Uint128 a, Uint128 b) {
242+
public static Int128[] mul128Unsigned(Int128 a, Int128 b) {
244243
final long a_hi = a.getHigh(); // a >>> 32;
245244
final long b_hi = b.getHigh(); // b >>> 32;
246245
final long a_lo = a.getLow(); // a & 0xFFFFFFFFL;
247246
final long b_lo = b.getLow(); // b & 0xFFFFFFFFL;
248247

249-
final Uint128 lo_prod = mul64(a_lo, b_lo); // a_lo * b_lo;
250-
final Uint128 med_prod1 = mul64(a_hi, b_lo); // a_hi * b_lo;
251-
final Uint128 med_prod2 = mul64(a_lo, b_hi); // a_lo * b_hi;
252-
final Uint128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
253-
final Uint128 hi_prod = mul64(a_hi, b_hi); // a_hi * b_hi;
248+
final Int128 lo_prod = mul64Unsigned(a_lo, b_lo); // a_lo * b_lo;
249+
final Int128 med_prod1 = mul64Unsigned(a_hi, b_lo); // a_hi * b_lo;
250+
final Int128 med_prod2 = mul64Unsigned(a_lo, b_hi); // a_lo * b_hi;
251+
final Int128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
252+
final Int128 hi_prod = mul64Unsigned(a_hi, b_hi); // a_hi * b_hi;
254253

255254
// the medium term could overflow
256255
//final long carry = (med_term+Long.MIN_VALUE < med_prod1+Long.MIN_VALUE) ? 1L<<32 : 0;
257-
final Uint128 carry = (med_term.getHigh()+Long.MIN_VALUE < med_prod1.getHigh()+Long.MIN_VALUE) ? new Uint128(1, 0) : new Uint128(0, 0);
256+
final Int128 carry = (med_term.getHigh()+Long.MIN_VALUE < med_prod1.getHigh()+Long.MIN_VALUE) ? new Int128(1, 0) : new Int128(0, 0);
258257

259258
//final long r_hi = (((lo_prod >>> 32) + med_term) >>> 32) + hi_prod + carry;
260259
final long lo_prod_hi = lo_prod.getHigh(); // (lo_prod >>> 32)
261-
final Uint128 intermediate = new Uint128(0, lo_prod_hi).add(med_term); // ((lo_prod >>> 32) + med_term)
260+
final Int128 intermediate = new Int128(0, lo_prod_hi).add(med_term); // ((lo_prod >>> 32) + med_term)
262261
final long intermediate_hi = intermediate.getHigh(); // (((lo_prod >>> 32) + med_term) >>> 32)
263-
final Uint128 r_hi = new Uint128(0, intermediate_hi).add(hi_prod).add(carry);
262+
final Int128 r_hi = new Int128(0, intermediate_hi).add(hi_prod).add(carry);
264263

265264
//final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
266265
final long med_term_lo = med_term.getLow(); // (med_term & 0xFFFFFFFFL)
267-
final Uint128 r_lo = new Uint128(med_term_lo, 0).add(lo_prod);
266+
final Int128 r_lo = new Int128(med_term_lo, 0).add(lo_prod);
268267

269268
//return new Uint128(r_hi, r_lo);
270-
return new Uint128[] {r_lo, r_hi};
269+
return new Int128[] {r_lo, r_hi};
271270
}
272271

273272
/**
@@ -277,20 +276,20 @@ public static Uint128 square64(long a) {
277276
* @param b Uint128
278277
* @return the low Uint128 of a*b
279278
*/
280-
public static Uint128 mul128_getLow(Uint128 a, Uint128 b) { // derived from mul128_v2
279+
public static Int128 mul128Unsigned_getLow(Int128 a, Int128 b) {
281280
final long a_hi = a.getHigh(); // a >>> 32;
282281
final long b_hi = b.getHigh(); // b >>> 32;
283282
final long a_lo = a.getLow(); // a & 0xFFFFFFFFL;
284283
final long b_lo = b.getLow(); // b & 0xFFFFFFFFL;
285284

286-
final Uint128 lo_prod = mul64(a_lo, b_lo); // a_lo * b_lo;
287-
final Uint128 med_prod1 = mul64(a_hi, b_lo); // a_hi * b_lo;
288-
final Uint128 med_prod2 = mul64(a_lo, b_hi); // a_lo * b_hi;
289-
final Uint128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
285+
final Int128 lo_prod = mul64Unsigned(a_lo, b_lo); // a_lo * b_lo;
286+
final Int128 med_prod1 = mul64Unsigned(a_hi, b_lo); // a_hi * b_lo;
287+
final Int128 med_prod2 = mul64Unsigned(a_lo, b_hi); // a_lo * b_hi;
288+
final Int128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
290289

291290
//final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
292291
final long med_term_lo = med_term.getLow(); // (med_term & 0xFFFFFFFFL)
293-
final Uint128 r_lo = new Uint128(med_term_lo, 0).add(lo_prod);
292+
final Int128 r_lo = new Int128(med_term_lo, 0).add(lo_prod);
294293

295294
//return new Uint128(r_hi, r_lo);
296295
return r_lo;
@@ -303,20 +302,20 @@ public static Uint128 mul128_getLow(Uint128 a, Uint128 b) { // derived from mul1
303302
* @param b Uint128
304303
* @return the low Uint128 of a*b
305304
*/
306-
public static Uint128 mul128MH_getLow(Uint128 a, Uint128 b) { // derived from mul128_v2
305+
public static Int128 mul128UnsignedMH_getLow(Int128 a, Int128 b) {
307306
final long a_hi = a.getHigh(); // a >>> 32;
308307
final long b_hi = b.getHigh(); // b >>> 32;
309308
final long a_lo = a.getLow(); // a & 0xFFFFFFFFL;
310309
final long b_lo = b.getLow(); // b & 0xFFFFFFFFL;
311310

312-
final Uint128 lo_prod = mul64_MH(a_lo, b_lo); // a_lo * b_lo;
313-
final Uint128 med_prod1 = mul64_MH(a_hi, b_lo); // a_hi * b_lo;
314-
final Uint128 med_prod2 = mul64_MH(a_lo, b_hi); // a_lo * b_hi;
315-
final Uint128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
311+
final Int128 lo_prod = mul64UnsignedMH(a_lo, b_lo); // a_lo * b_lo;
312+
final Int128 med_prod1 = mul64UnsignedMH(a_hi, b_lo); // a_hi * b_lo;
313+
final Int128 med_prod2 = mul64UnsignedMH(a_lo, b_hi); // a_lo * b_hi;
314+
final Int128 med_term = med_prod1.add(med_prod2); // med_prod1 + med_prod2;
316315

317316
//final long r_lo = ((med_term & 0xFFFFFFFFL) << 32) + lo_prod;
318317
final long med_term_lo = med_term.getLow(); // (med_term & 0xFFFFFFFFL)
319-
final Uint128 r_lo = new Uint128(med_term_lo, 0).add(lo_prod);
318+
final Int128 r_lo = new Int128(med_term_lo, 0).add(lo_prod);
320319

321320
//return new Uint128(r_hi, r_lo);
322321
return r_lo;
@@ -425,27 +424,27 @@ public static long mod128by64Unsigned(long u1, long u0, long v) {
425424
* @param bits
426425
* @return this << bits
427426
*/
428-
public Uint128 shiftLeft(int bits) {
427+
public Int128 shiftLeft(int bits) {
429428
if (bits<64) {
430429
long rh = (high<<bits) | (low>>>(64-bits));
431430
long rl = low<<bits;
432-
return new Uint128(rh, rl);
431+
return new Int128(rh, rl);
433432
}
434-
return new Uint128(low<<(bits-64), 0);
433+
return new Int128(low<<(bits-64), 0);
435434
}
436435

437436
/**
438437
* Shift this 'bits' bits to the right.
439438
* @param bits
440439
* @return this >>> bits
441440
*/
442-
public Uint128 shiftRight(int bits) {
441+
public Int128 shiftRight(int bits) {
443442
if (bits<64) {
444443
long rh = high>>>bits;
445444
long rl = (low>>>bits) | (high<<(64-bits));
446-
return new Uint128(rh, rl);
445+
return new Int128(rh, rl);
447446
}
448-
return new Uint128(0, high>>>(bits-64));
447+
return new Int128(0, high>>>(bits-64));
449448
}
450449

451450
/**

0 commit comments

Comments
 (0)