【问题标题】:Faster mod operation for large numbers in Java在 Java 中对大数进行更快的 mod 操作
【发布时间】:2019-08-02 19:47:17
【问题描述】:

我需要检查 X 是否可以被 Y 整除。在其他情况下,我不需要实际的余数。

我正在使用“mod”运算符。

if (X.mod(Y).equals(BigInteger.ZERO))
{
     do something
}

现在,我只对 X 可被 Y 整除感兴趣,在其他情况下我不需要实际余数。

当被除数固定时,寻找一种更快的方法来检查整除性。更准确地说,在进行 Lucas-Lehmer 测试之前检查具有许多较小素数的大数(可能是素数)。

我只是想知道,我们是否可以根据 X 和 Y 的最后一位或两位数做出一些假设(前瞻类型),我们可以决定是否选择 mod(当没有机会得到零)。

【问题讨论】:

  • 有什么理由要优化这么多吗?或者这是过早优化的情况?
  • 无论你想出什么,都不太可能比仅仅做模组更快。
  • 有一些选择,但您可能会从更广阔的视野中获得更多。 X 和 Y 是如何计算的?它们有有用的特性吗? Y 是否“固定”了足够长的时间,以至于为它预先计算某些东西是有意义的?
  • 与您要求的解决方案完全无关,但这种算术运算是记忆的理想选择。当您将函数的输入与输出一起缓存时,记忆是一种技术,因此对该函数的后续调用不会执行它,而是直接从缓存中返回答案。如果使用相同的数字进行调用,可能会比模数更快
  • 你考虑过位移吗?

标签: java biginteger mod


【解决方案1】:

Java BigIntegers(与大约 1980 年以来计算机中的大多数数字一样)是二进制的,因此可以通过查看最后一个“数字”(二进制数字 = 位)来优化的唯一模数是 2 的幂,并且只有 2 的素数幂是 21BigInteger.testBit(0) 直接测试。然而,大多数生成大应该素数的软件都是用于密码学的(如 RSA、Rabin、DH、DSA),并确保从一开始就不会测试偶数候选;参见例如FIPS186-4 A.1.1.2(或更早版本)。

由于您的实际目标并不如标题中所述,而是为了测试一个(大)整数是否不能被几个小素数的任何整除,因此数学上最快的方法是形成它们的乘积-- 通常是任何公倍数,最好是最小的,但对于不同的素数,乘积 LCM -- 并使用Euclid's algorithm 与候选计算它的 GCD。如果 GCD 为 1,则乘积中的 no 素因子与候选者是共同的,因此会除以候选者。这需要几个 BigInteger divideAndRemainder 操作,但它会在一个 fwoop 中处理您的所有测试。

一种中间方法是将乘积小于 231 或 263 的几个小素数“捆绑”起来,取BigInteger.mod(或.remainder)产品分别为.intValue().longValue(),并使用intlong 操作测试每个小素数的可分性(如果非零),这比BigInteger 快得多。如果需要,重复几束。 BigInteger.probablePrime 和相关例程正是这样做的(质数 3..41 与 long)对于高达 95 位的候选者,它认为 Erastosthenes 式筛子更有效。 (在这两种情况下,Miller-Rabin Lucas-Lehmer。)

在 Java 中测量这样的事情时,请记住,如果您执行一些“很多”方法,其中“很多”的确切定义可能会有所不同并且难以确定,所有常见的 JVM 都会 JIT 编译代码,从根本上改变性能。如果您正在经常这样做,请务必测量编译后的性能,如果您经常这样做,那么性能通常无关紧要。关于 Java 的“微基准测试”中的缺陷,这里存在 许多 问题。

【讨论】:

  • @user207421:在 1960 年代的大部分时间里,IBM 一直在 1400 系列中构建基于十进制的计算机。但 1980 年听起来确实很晚。
  • 图灵在他 1950 年的猜想论文中提到了二进制,而冯·诺伊曼在他 1945 年的第一稿备忘录中提到了二进制。我在 1971 年自己使用它,并在 1965 年左右被教授。传说俄罗斯人尝试过三元... @HenningMakholm
  • @HenningMakholm+ S/360-370-390-Z(和竞争对手)在很长一段时间内保持压缩十进制保持强劲,尽管我没有(可能没有人拥有)好的统计数据这就是我说“关于”的原因。也许我们应该说“早在 Java 开始之前”,因为这在这里很重要。欢呼。
【解决方案2】:

有一些算法可以检查可除性,但它是复数形式,每个算法都涵盖一组特定的数字,例如可被 3 整除,可被 4 整除等。可以找到一些算法的列表,例如在Wikipedia。没有通用的、高性能的算法可以用于任何给定的数字,否则发现它的人会很有名,并且那里的每一个可分割的实现都会使用它。

【讨论】:

  • 我看到了那些可分割的规则,对我的情况没有帮助。
  • @ManojBanik 好吧,实际上你的情况如何?
  • 找到一种更快的方法来检查分红固定时的可分性。更准确地说,在进行 Lucas-Lehmer 测试之前检查具有许多较小素数的大数(可能是素数)。 @Lothar。
  • @ManojBanik 如果您提前知道素数列表,那么有技巧
  • @ManojBanik 与常规除数测试相同的技巧与常数除数(不是除数规则,而是乘以除数模乘以二的幂)。但是如果除数很小,它们就不适用​​于 BigInteger,因为“big%small”的计算速度比“big*big”快。它适用于大的已知除数,或 long.. 的算术运算。所以我想这会让我们回到没有有用的技巧(E:here 就是一个例子)
猜你喜欢
  • 1970-01-01
  • 2013-05-05
  • 2020-05-13
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 2019-11-22
  • 1970-01-01
  • 2012-10-16
相关资源
最近更新 更多