最快的算法来判断一个大整数是否为质数?

8

我正在编写一个检测BigInteger是否为素数的方法。 我使用了以下代码/算法来检查给定数字是否为素数。 但是如果一个数字长达10位,这会非常缓慢并且需要很长时间。

 public boolean returnPrime(BigInteger testNumber){
        int divisorCounter=1;
        BigInteger index,i ;


        for ( index= new BigInteger("2"); index.compareTo(testNumber) !=1; index=index.add(new BigInteger("1"))){


            System.out.println(index);
            for(i= new BigInteger("2"); i.compareTo(index) != 1; i=i.add(new BigInteger("1"))){
            if((testNumber.mod(i).equals(BigInteger.ZERO) )){
            divisorCounter++;

            }

            if(divisorCounter>2){
            return false;
            }

            }       

        } 
    return true;

    }

有没有更好的算法可以处理BigInteger素数?我在Stackoverflow上找不到相关问题。如果你遇到过这样的问题,请告诉我,或者如果你有解决办法,欢迎分享你的想法。


1
在2之后,你只需要检查奇数。同时,在达到sqrt(n)后,你可以停止。 - Peter Lawrey
那么在第二个循环之前检查数字是否为质数并将其传递到第二个循环?这听起来不错,可以减少开销,因为我会消除所有偶数。 - Ram
1
而且 sqrt(n) 远小于 n - Peter Lawrey
3个回答

12

这里是使用最优化的方法,只测试到sqrt(n)并使用Miller-Rabin测试(截至Joni回答时):

public boolean returnPrime(BigInteger number) {
    //check via BigInteger.isProbablePrime(certainty)
    if (!number.isProbablePrime(5))
        return false;

    //check if even
    BigInteger two = new BigInteger("2");
    if (!two.equals(number) && BigInteger.ZERO.equals(number.mod(two)))
        return false;

    //find divisor if any from 3 to 'number'
    for (BigInteger i = new BigInteger("3"); i.multiply(i).compareTo(number) < 1; i = i.add(two)) { //start from 3, 5, etc. the odd number, and look for a divisor if any
        if (BigInteger.ZERO.equals(number.mod(i))) //check if 'i' is divisor of 'number'
            return false;
    }
    return true;
}

我测试了你的代码,必须说它很干净、简单!谢谢! - Ram
因为我们早先已经测试了能否被2整除,所以我们不必再测试是否可以被偶数因子整除。在最优化的版本中,我们只需要测试质因数。但这需要计算并存储最多sqrt(n)个质数在内存中。然而,早先测试数字是否为偶数可以将除法次数减半,因此这种优化是值得的。 - Juan Lopes
1
这段代码一点意义都没有。你使用了一个非常低的确定性水平来使用 isProbablePrime,然后进行了一个普通的暴力筛法,它不会在 sqrt(N) 处停止,而是一直到 N。为什么不使用高确定性水平的 isProbablyPrime 呢?这样会快得多。 - Jason S
1
@JasonS 它使用 isProbablePrime 作为概率优化步骤。当答案为负时,Miller-Rabin 概率测试是快速且精确的。您只需要在它返回 true 时进行检查,表示它可能是素数。此外,它会在 sqrt(N) 处停止,检查 i*i <= N 是否成立,而无需显式计算平方根。 - Juan Lopes
1
哦,我错过了第二部分,不知道为什么,抱歉;不过你仍然只使用置信度为1的Miller-Rabin测试 - (1/4)^5 = 90.2%。这太糟糕了;它是一个快速测试,所以你真的应该将“5”增加到更高的数字,比如20或30。另外,值得一提的是,计算sqrt(N)一次比重复计算i.multiply(i)要快得多。有一些减少乘法操作次数的方法比这两种方法都要快。 - Jason S
显示剩余2条评论

5

检查整数是否为“可能的质数”。如果不是,您可以确定它是复合数,并避免缓慢的分解。

if (!testNumber.isProbablePrime(5)) return false;

此外,您只需要对testNumber进行试除法,直到其平方根。如果K是合数,则其最小质因数必须小于或等于sqrt(K)。


还有确定性的Miller-Rabin测试变体,适用于给定范围内的数字。链接 - Niklas B.
为什么是 5?这不是很确定。 - Jason S
2
"P < 0.05?让我们发布吧!" :P - Joni

0

一些其他简单的改进是将可能的数字集限制为仅包含两个和奇数数字,在外部循环中,并且在内部循环中仅迭代到“index”的平方根(如果计算太困难,则为index / 2)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接