CompUInt128 implements CompUInt<UInt64, UInt64, CompUInt128> { @Override public CompUInt128 multiply(CompUInt128 other) { long thisLowAsLong = UInt.toUnLong(this.low); long thisMidAsLong = UInt.toUnLong(this.mid); long otherLowAsLong = UInt.toUnLong(other.low); long otherMidAsLong = UInt.toUnLong(other.mid); long t1 = thisLowAsLong * otherLowAsLong; long t2 = thisLowAsLong * otherMidAsLong; long t3 = thisLowAsLong * other.high; long t4 = thisMidAsLong * otherLowAsLong; long t5 = thisMidAsLong * otherMidAsLong; int t6 = (int) (this.mid * other.high); long t7 = this.high * otherLowAsLong; int t8 = (int) (this.high * other.mid); long m1 = (t1 >>> 32) + (t2 & 0xffffffffL); int m2 = (int) m1; long newMid = UInt.toUnLong(m2) + (t4 & 0xffffffffL); long newHigh = (t2 >>> 32) + t3 + (t4 >>> 32) + t5 + (UInt.toUnLong(t6) << 32) + t7 + (UInt.toUnLong(t8) << 32) + (m1 >>> 32) + (newMid >>> 32); return new CompUInt128(newHigh, (int) newMid, (int) t1); } CompUInt128(byte[] bytes);  CompUInt128(byte[] bytes, boolean requiresPadding);  CompUInt128(BigInteger value);   CompUInt128(long high, int mid, int low);   CompUInt128(UInt64 value);   CompUInt128(long value);   CompUInt128(CompUInt128 other); @Override CompUInt128 add(CompUInt128 other); @Override CompUInt128 multiply(CompUInt128 other); @Override CompUInt128 subtract(CompUInt128 other); @Override CompUInt128 negateUInt(); @Override boolean isZero(); @Override BigInteger toBigInteger(); @Override UInt64 getLeastSignificant(); @Override UInt64 getMostSignificant(); @Override UInt64 getLeastSignificantAsHigh(); @Override long toLong(); @Override int toInt(); @Override CompUInt128 shiftLowIntoHigh(); @Override int getLowBitLength(); @Override int getHighBitLength(); @Override String toString(); @Override byte[] toByteArray();  }
@Test public void testMultiply() { assertEquals( BigInteger.ZERO, new CompUInt128(0).multiply(new CompUInt128(0)).toBigInteger() ); assertEquals( BigInteger.ZERO, new CompUInt128(1).multiply(new CompUInt128(0)).toBigInteger() ); assertEquals( BigInteger.ZERO, new CompUInt128(0).multiply(new CompUInt128(1)).toBigInteger() ); assertEquals( BigInteger.ZERO, new CompUInt128(1024).multiply(new CompUInt128(0)).toBigInteger() ); assertEquals( BigInteger.ZERO, new CompUInt128(twoTo128.subtract(BigInteger.ONE)).multiply(new CompUInt128(0)) .toBigInteger() ); assertEquals( BigInteger.ONE, new CompUInt128(1).multiply(new CompUInt128(1)).toBigInteger() ); assertEquals( twoTo128.subtract(BigInteger.ONE), new CompUInt128(new CompUInt128(1)) .multiply(new CompUInt128(twoTo128.subtract(BigInteger.ONE))) .toBigInteger() ); assertEquals( twoTo128.subtract(BigInteger.ONE), new CompUInt128(twoTo128.subtract(BigInteger.ONE)).multiply(new CompUInt128(1)) .toBigInteger() ); assertEquals( new BigInteger("42").multiply(new BigInteger("7")), new CompUInt128(new BigInteger("42")).multiply(new CompUInt128(new BigInteger("7"))) .toBigInteger() ); assertEquals( new BigInteger("42").multiply(twoTo128.subtract(BigInteger.ONE)).mod(twoTo128), new CompUInt128(new BigInteger("42")) .multiply(new CompUInt128(twoTo128.subtract(BigInteger.ONE))) .toBigInteger() ); assertEquals( twoTo64.multiply(twoTo64.add(BigInteger.TEN)).mod(twoTo128), new CompUInt128(twoTo64) .multiply(new CompUInt128(twoTo64.add(BigInteger.TEN))) .toBigInteger() ); }