Java中长乘法的高位?

Java中长乘法的高位?,java,long-integer,multiplication,Java,Long Integer,Multiplication,在Java中,有没有办法获得两个longs的乘法的高一半?即由于溢出而消失的部分。(因此,128位结果的高64位) 我习惯于编写OpenCL代码,其中命令mul\u hi正好执行以下操作: 由于OpenCL可以在我的CPU上高效地完成这项工作,Java也应该能够做到这一点,但我找不到在Java中如何做到这一点(甚至无法有效地模拟其行为)。这在Java中是可能的吗?如果可能的话,怎么可能?你应该考虑使用a。你应该考虑使用a。假设你有两个长字符,x和y,和x=x\u hi*2^32+x\u lo,和

在Java中,有没有办法获得两个
long
s的乘法的高一半?即由于溢出而消失的部分。(因此,128位结果的高64位)

我习惯于编写OpenCL代码,其中命令
mul\u hi
正好执行以下操作:


由于OpenCL可以在我的CPU上高效地完成这项工作,Java也应该能够做到这一点,但我找不到在Java中如何做到这一点(甚至无法有效地模拟其行为)。这在Java中是可能的吗?如果可能的话,怎么可能?

你应该考虑使用a。

你应该考虑使用a。

假设你有两个长字符,
x
y
,和
x=x\u hi*2^32+x\u lo
,和
y=y\u hi*2^32+y\u lo

然后
x*y==(x_高*y高)*2^64+(x_高*y低+x_低*y高)*2^32+(x_低*y低)

因此,该乘积的高64位可按如下方式计算:

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);

假设你有两个长码,
x
y
,和
x=x\u hi*2^32+x\u lo
,和
y=y\u hi*2^32+y\u lo

然后
x*y==(x_高*y高)*2^64+(x_高*y低+x_低*y高)*2^32+(x_低*y低)

因此,该乘积的高64位可按如下方式计算:

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);

虽然误差是有界的(它最多可以比精确结果小2倍,而且永远不会比精确结果大),但大多数情况下,公认的解决方案都是错误的(66%)。这来自

  • 忽略
    x_lo*y_lo
    产品
  • 首先移位,然后添加
    x_高*y_低
    x_低*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;
result >>>= 32;

result += x_hi * y_lo + x_lo * y_hi;
result >>>= 32;
result += x_hi * y_hi;
在十亿个随机操作数上测试。应对拐角处的情况进行特殊测试并进行一些分析

处理负操作数将更加复杂,因为它将禁止使用无符号移位,并迫使我们处理中间结果溢出

如果速度无关紧要(而且很少如此),我会选择

 BigInteger.valueOf(x).multiply(BigInteger.valueOf(y))
     .shiftRight(64).longValue();

虽然误差是有界的(它最多可以比精确结果小2倍,而且永远不会比精确结果大),但大多数情况下,公认的解决方案都是错误的(66%)。这来自

  • 忽略
    x_lo*y_lo
    产品
  • 首先移位,然后添加
    x_高*y_低
    x_低*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;
result >>>= 32;

result += x_hi * y_lo + x_lo * y_hi;
result >>>= 32;
result += x_hi * y_hi;
在十亿个随机操作数上测试。应对拐角处的情况进行特殊测试并进行一些分析

处理负操作数将更加复杂,因为它将禁止使用无符号移位,并迫使我们处理中间结果溢出

如果速度无关紧要(而且很少如此),我会选择

 BigInteger.valueOf(x).multiply(BigInteger.valueOf(y))
     .shiftRight(64).longValue();

如果x或y可以为负值,则应使用Hacker's Delight函数(Henry s.Warren,Hacker's Delight,Addison Wesley,第二版,图8.2):

长x_高=x>>>32;
长x_低=x&0xffffffffffl;
长y_高=y>>>32;
长y_低=y&0xFFFFFFFFFFL;
长z2=x_低*y_低;
长t=x_高*y_低+(z2>>>32);
长z1=t&0xFFFFFFFFFFL;
长z0=t>>>32;
z1+=x_低*y_高;
返回x_高*y_高+z0+(z1>>>32);

如果x或y可以为负数,则应使用Hacker's Delight函数(Henry s.Warren,Hacker's Delight,Addison Wesley,第二版,图8.2):

长x_高=x>>>32;
长x_低=x&0xffffffffffl;
长y_高=y>>>32;
长y_低=y&0xFFFFFFFFFFL;
长z2=x_低*y_低;
长t=x_高*y_低+(z2>>>32);
长z1=t&0xFFFFFFFFFFL;
长z0=t>>>32;
z1+=x_低*y_高;
返回x_高*y_高+z0+(z1>>>32);

Java 9具有,根据Javadocs,“返回两个64位因子的128位乘积中最长有效的64位。”

Java 9具有,根据Javadocs,“返回两个64位因子的128位乘积中最长有效的64位。”

以下是Java的
Math.multiplyHigh(long,long)

公共静态长倍数高(长x,长y){
if(x<0 | | y<0){
//使用小亨利·S·沃伦第8-2节中的技巧。,
//黑客的喜悦(第二版)(艾迪生·韦斯利,2013),173-174。
长x1=x>>32;
长x2=x&0xffffffffffl;
长y1=y>>32;
长y2=y&0xFFFFFFFFFFL;
长z2=x2*y2;
长t=x1*y2+(z2>>32);
长z1=t&0xFFFFFFFFFFL;
长z0=t>>32;
z1+=x2*y1;
返回x1*y1+z0+(z1>>32);
}否则{
//使用两个基数为2^32的Karatsuba技术。
长x1=x>>>32;
长y1=y>>>32;
长x2=x&0xffffffffffl;
长y2=y&0xFFFFFFFFFFL;
长A=x1*y1;
长B=x2*y2;
长C=(x1+x2)*(y1+y2);
长K=C-A-B;
返回(((B>>>32)+K)>>>32)+A;
}
}

从Java9开始,它包含在Java.lang.Math中,可能应该直接调用它。发布源代码只是为了显示“幕后”正在发生的事情。

这里是Java的
Math.multiplyHigh(long,long)

公共静态长倍数高(长x,长y){
if(x<0 | | y<0){
//使用小亨利·S·沃伦第8-2节中的技巧。,
//黑客的喜悦(第二版)(艾迪生·韦斯利,2013),173-174。
长x1=x>>32;
长x2=x&0xffffffffffl;
长y1=y>>32;
长y2=y&0xFFFFFFFFFFL;
长z2=x2*y2;
长t=x1*y2+(z2>>32);
长z1=t&0xFFFFFFFFFFL;
长z0=t>>32;
z1+=x2*y1;
返回x1*y1+z0+(z1>>32);