【问题标题】:library for integer factorization in java or scalajava或scala中整数分解的库
【发布时间】:2012-07-21 13:54:15
【问题描述】:

关于如何实现分解有很多问题,但是对于生产用途,我宁愿使用开源库来立即获得高效且经过良好测试的东西。 我正在寻找的方法是这样的:

static int[] getPrimeFactors(int n)

对于 n=12,它会返回 {2,2,3}

一个库也可能有处理 long 甚至 BigInteger 类型的重载

问题不在于特定的应用程序,而在于拥有一个能够很好地处理这个问题的库。很多人认为根据数字的范围需要不同的实现,在这方面,我希望库在运行时选择最合理的方法。

高效并不是指“世界上最快的”(我不会为此在 JVM 上工作……),我只是指在一秒钟而不是一小时内处理 int 和 long range。

【问题讨论】:

  • 你需要处理多大的数字?
  • 因子经常被用来寻找别的东西(假设这不是你的程序所做的全部)。最有效的解决方案可能是直接找到您现在正在使用的因子。
  • @Thilo: int 的范围可以。我猜一个像样的库也会提供 long 和 BigInteger 的实现。
  • @PeterLawrey:找到质因数是一项相当普遍的任务,我不记得上次为什么需要它,无论如何,这次我需要它们来测试多项式是否是原始的. (因为可能存在一个库,但我确实想自己实现这部分)。我不太明白你的第二句话:-S
  • 我的第二个陈述的意思是,可能有一种更有效的方法来实现你想要的。在您的情况下,您想确定最大公约数是否为 1。这可以作为一个单一的功能来完成。假设你有很多系数,但一个是 1,你不需要确定其他系数的所有因素。

标签: java scala math factorization


【解决方案1】:

这取决于你想做什么。如果您的需求不大(例如,您想解决Project Euler 问题),Pollard 的 rho 算法的简单实现将立即找到高达 10 或 12 位的因子;如果这是您想要的,请告诉我,我可以发布一些代码。如果您想要一个用 Java 编写的更强大的因式分解程序,您可以查看 Dario Alpern 的 applet 背后的源代码;我不知道测试套件,它确实不是用开放的 api 设计的,但它确实有很多用户并且经过了很好的测试。大多数重型开源分解程序都是用 C 或 C++ 编写的,并使用 GMP 大整数库,但您可以通过您语言的外部函数接口访问它们;寻找像 gmp-ecmmsievepariyafu 这样的名称。如果这些不满足您,寻求更多帮助的好地方是Mersenne Forum

【讨论】:

  • Pollard 的 rho 保证可以找到一个因子(如果存在)?我没想到,这可能会使它不合适。
  • @RexKerr:我认为答案是肯定的,Pollard rho 保证会找到一个因素(如果存在),但我不确定我能否证明这一点。如果您尝试的第一个随机数生成器遇到循环,您可能必须切换到不同的随机数生成器。
  • 感谢您的指点。关于 Pollard 的 Rho:根据 Wikipedia,这个算法对于素数总是失败,所以它需要先运行素数测试:-S 但正如你所说,对于几个项目的 Euler 问题,它完全没问题。
【解决方案2】:

如果你想解决你的问题,而不是得到你想要的,你想要一张桌子。您可以使用愚蠢的缓慢方法预先计算它,存储它,然后以微秒为单位查找任何数字的因子。特别是,您想要一个表格,其中最小因子列在与数字对应的索引中 - 如果您使用试除法删除一些最小的素数,内存效率会更高 - 然后沿着表格向下走,直到你打了一个 1(意味着没有除数;你剩下的是素数)。这将只占用每个表条目两个字节,这意味着您可以将所有内容存储在比智能手机更强大的任何现代机器上。

如果您有兴趣,我可以演示如何创建它,并展示如何以比您希望通过一个活跃的社区和复杂算法的单元测试实现的可靠性更高的方式检查它是否正确(除非您运行算法生成此表并验证一切正常)。

【讨论】:

  • 我猜你假设 int 并忽略了对 long 和 BigInteger 的概括。即使使用 int 表也很大,而且没有必要。试除以 2 和从 3 到 sqrt(2^31-1) 的奇数简单快速,无需辅助存储。
  • @user448810 - 除以 20k 个数字对您来说足够快吗?那你为什么还要问呢?这很容易实现。
  • 你把我和原来的海报搞混了。我只是指出,对于表格足够小以至于可以理解的范围,不需要该表格,因为试验划分就足够了。
  • @user448810 - 哎呀,我确实让你感到困惑。但是,再一次,试除法比表法慢一千倍。所以这取决于你在做什么,不是吗?由于 OP 想要一种有效的 int 方法,因此试划分可能不够
  • 我认为我们在这里达成了激烈的协议。问题是原始发布者在评论中修改了他的要求,说处理 long 和 BigInteger 会很好。一个表已经在使用 int (它有十亿个条目,这将需要大量时间才能从磁盘读取到内存中)。我在我的博客上讨论了factor tables,以及许多其他素数的东西。
【解决方案3】:

我需要它们来测试多项式是否是原始的。

这比试图找出所有数字的因数要快。

public static boolean gcdIsOne(int[] nums) {
    int smallest = Integer.MAX_VALUE;
    for (int num : nums) {
        if (num > 0 && smallest < num)
            smallest = num;
    }
    OUTER:
    for (int i = 2; i * i <= smallest; i = (i == 2 ? 3 : i + 2)) {
        for (int num : nums) {
            if (num % i != 0)
                continue OUTER;
        }
        return false;
    }
    return true;
}

【讨论】:

  • 对不起,我没想到会这样。我应该更精确:我正在使用一个素数 p 和一个具有 Zp 系数的一元不可约多项式 f(x)。我认为这种情况下的算法更复杂(在我的书中它涉及模幂运算,指数是 p-1 的每个素数)
【解决方案4】:

我在 scala 中尝试过这个功能。这是我的结果:

def getPrimeFactores(i: Int) = {
  def loop(i: Int, mod: Int, primes: List[Int]): List[Int] = {
    if (i < 2) primes      // might be i == 1 as well and means we are done
    else {
      if (i % mod == 0) loop(i / mod, mod, mod :: primes)
      else loop(i, mod + 1, primes)
    }
  }
  loop(i, 2, Nil).reverse
}

我尝试让它尽可能地实用。
if (i % mod == 0) loop(i / mod, mod, mod :: primes) 检查我们是否找到了除数。如果我们这样做了,我们将它添加到素数并将 i 除以 mod。
如果我们没有找到新的除数,我们只是增加除数。
loop(i, 2, Nil).reverse初始化函数并递增命令结果。

【讨论】:

  • 不需要重置为 2,因为mod 已经是i 的最小素数了
  • 感谢您提供此源代码,但我正在寻找一个具有不错的单元测试套件、多个用户的开源库... 像 apache.commons.math 之类的东西,据我所知,不要实现这样的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-05
  • 2013-02-08
  • 2015-03-09
  • 2015-09-17
  • 1970-01-01
相关资源
最近更新 更多