大数的素数分解

Posted

技术标签:

【中文标题】大数的素数分解【英文标题】:Prime factorization of large numbers [closed] 【发布时间】:2012-09-03 17:26:09 【问题描述】:

我想找到小于 10^12 的。 我得到了这段代码(在 java 中):

public static List<Long> primeFactors(long numbers) 
        long n = numbers;
        List<Long> factors = new ArrayList<Long>();
        for (long i = 2; i <= n / i; i++) 
            while (n % i == 0) 
                factors.add(i);
                n /= i;
            
        
        if (n > 1) 
            factors.add(n);
        
        return factors;
    

首先,上述算法的复杂度是多少??我很难找到它??

对于大数的素数来说,它也太慢了。

有没有更好的算法,或者如何优化这个算法??

【问题讨论】:

对于单个号码,您不会好很多。您可以进行一些预先计算,但这仅在您需要进行大量分解时才有意义。 我会研究 Pollards Rho 算法。您的数字范围实际上并不需要它,但它可能会更好。 可能重复:Prime Factorization Program in Java @harold - 我不确定那是 Pollard 的 Rho。看起来像是从2SQRT(n) 的试用部门。我相信SQRT(n) 是正确的:n / i 有点混乱,但我相信循环在i^2 &lt;= n 时执行,相当于i &lt;= SQRT(n)。内部while 看起来会删除多个素数。例如,如果一个数字是 4 的倍数,它会将 2 添加到列表中两次。 @noloader 是的,这是试用部门,这就是为什么我推荐别的东西 【参考方案1】:

如果你想分解许多个大数,那么你最好先找到直到sqrt(n)的素数(例如使用Sieve of Eratosthenes)。然后你只需要检查这些素数是否是因子而不是测试所有i &lt;= sqrt(n)

【讨论】:

即使我找到了直到sqrt(n) 的所有素数,如果我被要求计算素数分解产生k 素数t 次数的数字,这种方法将性能恶化。你能推荐一些更有效的方法吗?【参考方案2】:

复杂度为O(sqrt(n))。查sqrt(n)之后的数字是没有意义的。

这意味着对于10^12,最多需要1 000 000 次迭代,这并不慢。

【讨论】:

对高达 10^6 的素数进行预计算将使其速度提高约 10 倍【参考方案3】:

因式分解大数是一个难题,这也是加密算法使用大素数的因数来使加密难以破解的部分原因。

public static void main(String... args)  
    int nums = 100;
    for (int i = 0; i < nums; i++) 
        long start = System.nanoTime();
        primeFactors(Long.MAX_VALUE - i);
        long time = System.nanoTime() - start;
        if (time > 100e6)
            System.out.println((Long.MAX_VALUE-i) + " took "+time/1000000+" ms.");
    


public static List<Long> primeFactors(long n) 
    List<Long> factors = new ArrayList<Long>();
    while (n % 2 == 0 && n > 0) 
        factors.add(2L);
        n /= 2;
    

    for (long i = 3; i * i <= n; i+=2) 
        while (n % i == 0) 
            factors.add(i);
            n /= i;
        
    
    if (n > 1)
        factors.add(n);

    return factors;

打印

9223372036854775806 took 3902 ms.
9223372036854775805 took 287 ms.
9223372036854775804 took 8356 ms.
9223372036854775797 took 9519 ms.
9223372036854775796 took 1507 ms.
9223372036854775794 took 111 ms.
9223372036854775788 took 184 ms.

如果您将 Long.MAX_VALUE 替换为 1000000000000L,它们都会在 20 毫秒内分解。

【讨论】:

+1 提到这就是加密算法依赖大素数的原因 自己做优化没有意义(这是编译器的工作)。您可以使用n % 2 == 0n /= 2,这将使代码更具可读性。实际的优化是将i++ 替换为i += 2,因为您已经检查了2 的可分性。预先计算 sqrt(n) 而不是在每次迭代中执行 i*i 也可以产生更好的结果(我已经看到这对 C++ 代码有很大影响) 另外,更重要的是,您应该使用-ea 运行您的代码:如果数字的质因数大于平方根,则断言是错误的:尝试运行primeFactors(6)。 OP的代码至少是正确的:) @NiklasB。我的意思是 += 2 :| 我删除了断言,因为它仍然是错误的;)【参考方案4】:

一个更好的算法可能是以下搜索素数(我的 java 生锈了,所以可能需要一些调整来编译它)。

if (number % 2)
   factors.append(2)
if (number % 3)
   factors.append(3)

for(int n = 0; n < sqrt(number)/6; n++)

   if (number % (6 * n + 1))
      factors.append(6 * n + 1);
   if (number % (6 * n - 1))
      factors.append(6 * n - 1);

【讨论】:

不确定这个算法想要达到什么效果! @Nuclearman 为什么要把“sqrt(number/6)”中的数字除以 6? 公平点,看起来应该在平方根之外。 附加因子的条件似乎是互补的。

以上是关于大数的素数分解的主要内容,如果未能解决你的问题,请参考以下文章

数学#素数判定Miller_Rabin+大数因数分解Pollard_rho算法 POJ 1811&2429

Prime Test POJ - 1811(素性检测+大数分解)

大素数判断和素因子分解(miller-rabin,Pollard_rho算法) 玄学快

Java中带指数的素数分解

具有素数列表的高效素数分解算法

蛮力,单线程素数分解