Is there any way to get the high half of the multiplication of two long
s in Java? I.e. the part that vanishes due to overflow. (So the upper 64 bits of the 128-
Java 9 has Math.multiplyHigh, which according to the Javadocs "Returns as a long the most significant 64 bits of the 128-bit product of two 64-bit factors."
Some of described cases above works wrong. First of all you have to ask yourself what types of operands do you treat (signed/unsigned).
There is a modified code from sample above that is fixed for carry flag (treat x & y as unsigned 64-bit values):
public static long productHi(long x, long y) {
final long x_hi = x >>> 32;
final long y_hi = y >>> 32;
final long x_lo = x & 0xFFFFFFFFL;
final long y_lo = y & 0xFFFFFFFFL;
long result = (x_lo * y_lo) >>> 32;
long a = x_hi * y_lo;
long b = x_lo * y_hi;
long sum = a + b + result;
long carry = ((a & b) | (~sum & (a ^ b))) >>> 63;
result = (sum >>> 32) + x_hi * y_hi + (carry << 32);
return result;
}
If either x or y can be negative, you should use Hacker's Delight function (Henry S. Warren, Hacker's Delight, Addison-Wesley, 2nd edition, Fig. 8.2):
long x_high = x >>> 32;
long x_low = x & 0xFFFFFFFFL;
long y_high = y >>> 32;
long y_low = y & 0xFFFFFFFFL;
long z2 = x_low * y_low;
long t = x_high * y_low + (z2 >>> 32);
long z1 = t & 0xFFFFFFFFL;
long z0 = t >>> 32;
z1 += x_low * y_high;
return x_high * y_high + z0 + (z1 >>> 32);
You should look at using a BigInteger.
Let's say you have two longs, x
and y
, and x = x_hi * 2^32 + x_lo
, and y = y_hi * 2^32 + y_lo
.
Then x * y == (x_hi * y_hi) * 2^64 + (x_hi * y_lo + x_lo * y_hi) * 2^32 + (x_lo * y_lo)
.
The high 64 bits of that product can, therefore, be computed as follows:
long x_hi = x >>> 32;
long y_hi = y >>> 32;
long x_lo = x & 0xFFFFFFFFL;
long y_lo = y & 0xFFFFFFFFL;
long prod_hi = (x_hi * y_hi) + ((x_ hi * y_lo) >>> 32) + ((x_lo * y_hi) >>> 32);
The accepted solution is wrong most of the time (66%), though the error is bounded (it can be smaller than the exact result by at most 2 and it can never be bigger). This comes from
x_lo * y_lo
productx_hi * y_lo
and x_lo * y_hi
My solution seems to always work for non-negative operands.
final long x_hi = x >>> 32;
final long y_hi = y >>> 32;
final long x_lo = x & 0xFFFFFFFFL;
final long y_lo = y & 0xFFFFFFFFL;
long result = x_lo * y_lo;
result >>>= 32;
result += x_hi * y_lo + x_lo * y_hi;
result >>>= 32;
result += x_hi * y_hi;
Tested on a billion random operands. There should be a special test for corner cases and some analysis.
Dealing with negative operands would be more complicated as it'd prohibit using the unsigned shift and force us to handle intermediate result overflow.
In case speed doesn't matter much (and it rarely does), I'd go for
BigInteger.valueOf(x).multiply(BigInteger.valueOf(y))
.shiftRight(64).longValue();