Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/374.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在Java中处理128位的小尾端乘法而不使用BigInteger_Java_Bit Manipulation_64 Bit_Biginteger_Multiplication - Fatal编程技术网

如何在Java中处理128位的小尾端乘法而不使用BigInteger

如何在Java中处理128位的小尾端乘法而不使用BigInteger,java,bit-manipulation,64-bit,biginteger,multiplication,Java,Bit Manipulation,64 Bit,Biginteger,Multiplication,我需要以最快的方式乘以两个8字节(64位)数组。字节数组是小端的。数组可以用ByteBuffer包装,并被视为小endian,以便轻松解析正确表示字节的java“long”值(但不是真正的标称值,因为java long是一种补足) Java处理大型数学的标准方法是BigInteger。但是这种实现速度慢而且没有必要,因为我严格地使用64位x 64位。此外,您不能将“long”值转换为1,因为标称值不正确,我也不能直接使用字节数组,因为它是小端。我需要能够做到这一点,而不必使用更多的内存/CPU来

我需要以最快的方式乘以两个8字节(64位)数组。字节数组是小端的。数组可以用ByteBuffer包装,并被视为小endian,以便轻松解析正确表示字节的java“long”值(但不是真正的标称值,因为java long是一种补足)

Java处理大型数学的标准方法是BigInteger。但是这种实现速度慢而且没有必要,因为我严格地使用64位x 64位。此外,您不能将“long”值转换为1,因为标称值不正确,我也不能直接使用字节数组,因为它是小端。我需要能够做到这一点,而不必使用更多的内存/CPU来反转阵列。这种类型的乘法应该能够每秒执行1m+次。无论如何,BigInteger并不能真正满足这一要求,所以我试图通过将高阶位与低阶位分开来实现这一点,但我无法让它一致地工作

仅高阶位代码仅适用于long的子集,因为即使是中间加法也可能溢出。我从这个答案中得到了我的当前代码

从128位乘法中获取高/低阶位是否有更通用的模式?这适用于最大的长期价值

编辑:


FWIW我已经准备好了答案。。“不能用java做,C++做,JNI调用”。尽管我希望有人能在这之前给出一个java解决方案。

这可以在没有BigInteger的情况下手动完成,方法是将long拆分为两半,创建部分乘积,然后求和。当然,金额的低一半可以忽略不计

部分乘积重叠,如下所示:

  LL
 LH
 HL
HH
因此,必须将LH和HL的高半部添加到高结果中,此外,LH和HL的低半部以及LL的高半部可能会携带到结果的高半部的位中。不使用LL的下半部分

因此,类似这样的情况(仅经过轻微测试):

这当然会将输入视为无符号,这并不意味着它们必须是正的,因为Java会将它们视为正的,您完全可以输入-1501598000831384712L和-73593267070715720L,然后输出,正如所确认的


<>如果您准备与本机代码接口,在C++中使用MSVC,您可以使用GCC/CLAN,可以使产品成为<代码> > UTIT128YTT < /代码>,只需将其右移,即代码生成,它不会导致完整的128x128乘法运算。

找到一个以优化方式处理该运算的数学库吗?您使用过吗?我想知道您的使用案例是什么,使得内置的64位长乘法运算不充分。我已经找过一个库,但找不到。每个人都说使用BigInteger,但我并没有将1000位数字相乘,所以它的开销太大了。我已经研究了未签名的实用程序方法,但它们只是通过转换为字符串来增加开销,这是不必要的。这是我的用例:-1501598000831384712LX-73593267071577287L;你确定不能简单地将这两个长度相乘吗?“无符号加法、减法和乘法是相同的:我们只需要使用普通的+、-和*运算符即可。”非常好。这就是我要寻找的,其他代码只是有一些导致溢出的缺陷。谢谢FWIW如果对本机代码执行相同的操作,那么其性能应该要差得多。本机代码只需一次乘法即可完成,而不是4次乘法加上一堆填充符。一个JNI调用当然有开销,所以希望您可以将整个循环移动到本机端。明白了。这最终可能会发生,但至少在将来的参考中,我将了解用Java实现这一点的最有效的方法@DanWatson:
另一个代码只是在添加中有一些缺陷,导致了溢出
,如果您可以很容易地编辑或注释该其他代码,请务必这样做。@greybeard可以将
t00
的缩放上半部分添加到
t01
(或
t10
)但我找不到一种真正有帮助的方法——尽管我没有对它进行基准测试,也许在实践中稍微不同的结构很重要。
static long hmul(long x, long y) {
    long m32 = 0xffffffffL;
    // split
    long xl = x & m32;
    long xh = x >>> 32;
    long yl = y & m32;
    long yh = y >>> 32;
    // partial products
    long t00 = xl * yl;
    long t01 = xh * yl;
    long t10 = xl * yh;
    long t11 = xh * yh;
    // resolve sum and carries
    // high halves of t10 and t01 overlap with the low half of t11
    t11 += (t10 >>> 32) + (t01 >>> 32);
    // the sum of the low halves of t10 + t01 plus
    // the high half of t00 may carry into the high half of the result
    long tc = (t10 & m32) + (t01 & m32) + (t00 >>> 32);
    t11 += tc >>> 32;
    return t11;
}