我正在尝试找到检查给定数字是否为素数的最快方法(在Java中)。以下是我提出的几种素性测试方法。有没有比第二个实现更好的方法(isPrime2)?
public class Prime {
public static boolean isPrime1(int n) {
if (n <= 1) {
return false;
}
if (n == 2) {
return true;
}
for (int i = 2; i <= Math.sqrt(n) + 1; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
public static boolean isPrime2(int n) {
if (n <= 1) {
return false;
}
if (n == 2) {
return true;
}
if (n % 2 == 0) {
return false;
}
for (int i = 3; i <= Math.sqrt(n) + 1; i = i + 2) {
if (n % i == 0) {
return false;
}
}
return true;
}
}
public class PrimeTest {
public PrimeTest() {
}
@Test
public void testIsPrime() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException {
Prime prime = new Prime();
TreeMap<Long, String> methodMap = new TreeMap<Long, String>();
for (Method method : Prime.class.getDeclaredMethods()) {
long startTime = System.currentTimeMillis();
int primeCount = 0;
for (int i = 0; i < 1000000; i++) {
if ((Boolean) method.invoke(prime, i)) {
primeCount++;
}
}
long endTime = System.currentTimeMillis();
Assert.assertEquals(method.getName() + " failed ", 78498, primeCount);
methodMap.put(endTime - startTime, method.getName());
}
for (Entry<Long, String> entry : methodMap.entrySet()) {
System.out.println(entry.getValue() + " " + entry.getKey() + " Milli seconds ");
}
}
}
答案 0 :(得分:69)
这是另一种方式:
boolean isPrime(long n) {
if(n < 2) return false;
if(n == 2 || n == 3) return true;
if(n%2 == 0 || n%3 == 0) return false;
long sqrtN = (long)Math.sqrt(n)+1;
for(long i = 6L; i <= sqrtN; i += 6) {
if(n%(i-1) == 0 || n%(i+1) == 0) return false;
}
return true;
}
和BigInteger's isProbablePrime(...)
对所有32位int
都有效。
修改强>
请注意,isProbablePrime(certainty)
并不总能产生正确的答案。当确定性偏低时,会产生误报,如评论中提到的@ dimo414。
不幸的是,我找不到声称isProbablePrime(certainty)
对所有(32位)int
有效的来源(给定足够的确定性!)。
所以我进行了几次测试。我创建了一个大小为BitSet
的{{1}}代表所有不均匀的数字,并使用素数筛查找Integer.MAX_VALUE/2
范围内的所有素数。然后我从1..Integer.MAX_VALUE
循环测试每个i=1..Integer.MAX_VALUE
。
对于确定性5和10,new BigInteger(String.valueOf(i)).isProbablePrime(certainty) == isPrime(i)
沿线产生误报。但是使用isProbablePrime(...)
,没有测试失败。
这是我的试验台:
isProbablePrime(15)
我跑过去跑的那个:
import java.math.BigInteger;
import java.util.BitSet;
public class Main {
static BitSet primes;
static boolean isPrime(int p) {
return p > 0 && (p == 2 || (p%2 != 0 && primes.get(p/2)));
}
static void generatePrimesUpTo(int n) {
primes = new BitSet(n/2);
for(int i = 0; i < primes.size(); i++) {
primes.set(i, true);
}
primes.set(0, false);
int stop = (int)Math.sqrt(n) + 1;
int percentageDone = 0, previousPercentageDone = 0;
System.out.println("generating primes...");
long start = System.currentTimeMillis();
for(int i = 0; i <= stop; i++) {
previousPercentageDone = percentageDone;
percentageDone = (int)((i + 1.0) / (stop / 100.0));
if(percentageDone <= 100 && percentageDone != previousPercentageDone) {
System.out.println(percentageDone + "%");
}
if(primes.get(i)) {
int number = (i * 2) + 1;
for(int p = number * 2; p < n; p += number) {
if(p < 0) break; // overflow
if(p%2 == 0) continue;
primes.set(p/2, false);
}
}
}
long elapsed = System.currentTimeMillis() - start;
System.out.println("finished generating primes ~" + (elapsed/1000) + " seconds");
}
private static void test(final int certainty, final int n) {
int percentageDone = 0, previousPercentageDone = 0;
long start = System.currentTimeMillis();
System.out.println("testing isProbablePrime(" + certainty + ") from 1 to " + n);
for(int i = 1; i < n; i++) {
previousPercentageDone = percentageDone;
percentageDone = (int)((i + 1.0) / (n / 100.0));
if(percentageDone <= 100 && percentageDone != previousPercentageDone) {
System.out.println(percentageDone + "%");
}
BigInteger bigInt = new BigInteger(String.valueOf(i));
boolean bigIntSays = bigInt.isProbablePrime(certainty);
if(isPrime(i) != bigIntSays) {
System.out.println("ERROR: isProbablePrime(" + certainty + ") returns "
+ bigIntSays + " for i=" + i + " while it " + (isPrime(i) ? "is" : "isn't" ) +
" a prime");
return;
}
}
long elapsed = System.currentTimeMillis() - start;
System.out.println("finished testing in ~" + ((elapsed/1000)/60) +
" minutes, no false positive or false negative found for isProbablePrime(" + certainty + ")");
}
public static void main(String[] args) {
int certainty = Integer.parseInt(args[0]);
int n = Integer.MAX_VALUE;
generatePrimesUpTo(n);
test(certainty, n);
}
}
在我的机器上生成素数大约需要30秒。 java -Xmx1024m -cp . Main 15
中所有i
的实际测试时间约为2小时15分钟。
答案 1 :(得分:43)
这是最优雅的方式:
public static boolean isPrime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
Java 1.4+。不需要进口。
太短了。真漂亮。
答案 2 :(得分:12)
查看AKS primality test(及其各种优化)。它是在多项式时间内运行的确定性素性测试。
中有一种算法实现答案 3 :(得分:10)
你迈出了消除2的所有倍数的第一步。
然而,你为何停在那里?你可以消除除3之外的所有3的倍数,除了5之外的所有5的倍数等等。
当你按照这个推理得出结论时,你会得到Sieve of Eratosthenes。
答案 4 :(得分:4)
您的算法适用于相当小的数字。对于大数字,应该使用高级算法(例如基于椭圆曲线)。另一个想法是使用一些“pseuso-primes”测试。这些将很快测试一个数字是一个素数,但它们不是100%准确。但是,它们可以帮助您比使用算法更快地排除某些数字。
最后,尽管编译器可能会为您优化,但您应该写:
int max = (int) (Math.sqrt(n) + 1);
for (int i = 3; i <= max; i = i + 2) {
}
答案 5 :(得分:4)
如果你只是想找到一个数字是否为素数就足够了,但是如果你想找到从0到n的所有素数,一个更好的选择将是Sieve of Eratosthenes
但它将取决于java对数组大小等的限制。
答案 6 :(得分:3)
你所写的是最常见的程序员所做的,而且大部分时间都应该足够。
但是,如果您使用的是“最佳科学算法”,则会有许多变体(具有不同程度的确定性)记录http://en.wikipedia.org/wiki/Prime_number。
例如,如果您有一个70位数字,JVM的物理限制可能会阻止您的代码运行,在这种情况下您可以使用“Sieves”等。
同样,就像我说的那样,如果这是一个编程问题或软件中使用的一般问题,你的代码应该是完美的:)
答案 7 :(得分:3)
由于Jaeschke(1993)的快速测试是Miller-Rabin测试的确定性版本,其在4,759,123,141之下没有误报,因此可以应用于Java int
。
// Given a positive number n, find the largest number m such
// that 2^m divides n.
private static int val2(int n) {
int m = 0;
if ((n&0xffff) == 0) {
n >>= 16;
m += 16;
}
if ((n&0xff) == 0) {
n >>= 8;
m += 8;
}
if ((n&0xf) == 0) {
n >>= 4;
m += 4;
}
if ((n&0x3) == 0) {
n >>= 2;
m += 2;
}
if (n > 1) {
m++
}
return m;
}
// For convenience, handle modular exponentiation via BigInteger.
private static int modPow(int base, int exponent, int m) {
BigInteger bigB = BigInteger.valueOf(base);
BigInteger bigE = BigInteger.valueOf(exponent);
BigInteger bigM = BigInteger.valueOf(m);
BigInteger bigR = bigB.modPow(bigE, bigM);
return bigR.intValue();
}
// Basic implementation.
private static boolean isStrongProbablePrime(int n, int base) {
int s = val2(n-1);
int d = modPow(b, n>>s, n);
if (d == 1) {
return true;
}
for (int i=1; i < s; i++) {
if (d+1 == n) {
return true;
}
d = d*d % n;
}
return d+1 == n;
}
public static boolean isPrime(int n) {
if ((n&1) == 0) {
return n == 2;
}
if (n < 9) {
return n > 1;
}
return isStrongProbablePrime(n, 2) && isStrongProbablePrime(n, 7) && isStrongProbablePrime(n, 61);
}
这对long
变量不起作用,但是另一个测试确实如此:BPSW测试没有最多2 ^ 64的反例。这基本上包括一个像上面那样的2强可能的素数测试,接着是一个强大的Lucas测试,这个测试有点复杂但没有根本不同。
这两项测试都比任何类型的试验分析都要快得多。
答案 8 :(得分:3)
我认为这种方法是最好的。至少对我而言 -
public static boolean isPrime(int num)
{
for (int i = 2; i<= num/i; i++)
{
if (num % i == 0)
{
return false;
}
}
return num > 1;
}
答案 9 :(得分:3)
根据您需要测试的数字的长度,您可以预先计算小值(n <10 ^ 6)的素数列表,如果要求的数字在此范围内,则首先使用该素数列表。这当然是最快的方式。 与其他答案中提到的一样,Sieve of Eratosthenes是生成此类预先计算列表的首选方法。
如果您的数字大于此数,则可以使用Rabin的素数测试。 Rabin primality test
答案 10 :(得分:2)
当然有数百种素性测试,根据数量大小,特殊形式,因子大小等各种优点和缺点。
然而,在java中我找到了最有用的一个:
BigInteger.valueOf(long/int num).isProbablePrime(int certainty);
它已经实现了,并且非常快(我发现1000x1000矩阵需要大约6秒才能填充长0-2 ^ 64和15的确定性)并且可能比我们凡人想出的任何东西都更优化。
它使用Baillie–PSW primality test的版本,其中没有已知的反例。 (虽然它可能会使用稍微弱一点的测试版本,有时可能会出错。也许)
答案 11 :(得分:1)
算法效率:O(n ^(1/2))算法
注意:下面的示例代码包含计数变量和调用打印功能以便打印结果:
import java.util.*;
class Primality{
private static void printStats(int count, int n, boolean isPrime) {
System.err.println( "Performed " + count + " checks, determined " + n
+ ( (isPrime) ? " is PRIME." : " is NOT PRIME." ) );
}
/**
* Improved O( n^(1/2)) ) Algorithm
* Checks if n is divisible by 2 or any odd number from 3 to sqrt(n).
* The only way to improve on this is to check if n is divisible by
* all KNOWN PRIMES from 2 to sqrt(n).
*
* @param n An integer to be checked for primality.
* @return true if n is prime, false if n is not prime.
**/
public static boolean primeBest(int n){
int count = 0;
// check lower boundaries on primality
if( n == 2 ){
printStats(++count, n, true);
return true;
} // 1 is not prime, even numbers > 2 are not prime
else if( n == 1 || (n & 1) == 0){
printStats(++count, n, false);
return false;
}
double sqrtN = Math.sqrt(n);
// Check for primality using odd numbers from 3 to sqrt(n)
for(int i = 3; i <= sqrtN; i += 2){
count++;
// n is not prime if it is evenly divisible by some 'i' in this range
if( n % i == 0 ){
printStats(++count, n, false);
return false;
}
}
// n is prime
printStats(++count, n, true);
return true;
}
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
while(scan.hasNext()) {
int n = scan.nextInt();
primeBest(n);
System.out.println();
}
scan.close();
}
}
输入素数2147483647时,会产生以下输出:
执行23170次检查,确定2147483647为PRIME。
答案 12 :(得分:1)
我在这里优化了试验部门: 它返回一个布尔值。 除了isPrime(n)之外的方法也是必需的。
static boolean[] smlprime = {false, false, true, true, false, true, false, true, false, false, false, true, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, true, false, false, false, true, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, true, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, true, false, false, false, false, false, false, false, true, false, false, false, false, false, true, false, false};
public static boolean isPrime(long n) { //optimised
if (n < 2) {
return false;
}
if (n < smlprime.length) //less than smlprime.length do not need to be checked
{
return smlprime[(int) n]; //lol already checked
}
long[] dgt = longDigits(n);
long ones = dgt[dgt.length - 1];
if (ones % 2 == 0) {
return false;
}
if (ones == 0 || ones == 5) {
return false;
}
if (digitadd(n) % 3 == 0) {
return false;
}
if (n % 7 == 0) {
return false;
}
if (Square(n)) {
return false;
}
long hf = (long) Math.sqrt(n);
for (long j = 11; j < hf; j = nextProbablePrime(j)) {
//System.out.prlongln(Math.sqrt(i));
if (n % j == 0) {
return false;
}
//System.out.prlongln("res"+res);
}
return true;
}
public static long nextProbablePrime(long n) {
for (long i = n;; i++) {
if (i % 2 != 0 && i % 3 != 0 && i % 7 != 0) {
return i;
}
}
}
public static boolean Square(long n) {
long root = (long) Math.sqrt(n);
return root * root == n;
}
public static long[] longDigits(long n) {
String[] a = Long.toString(n).split("(?!^)");
long[] out = new long[a.length];
for (int i = 0; i < a.length; i++) {
out[i] = Long.parseLong(a[i]);
}
return out;
}
public static long digitadd(long n) {
long[] dgts = longDigits(n);
long ans = 0;
for (long i : dgts) {
ans += i;
}
return ans;
}
答案 13 :(得分:0)
在Intel Atom @ 1.60GHz,2GB RAM,32位操作系统上进行了测试
测试结果:
Long.MAX_VALUE = 9223372036854775807以下的最大质数是9223372036854775783
经过时间为171499毫秒或2分零51秒
public class PrimalityTest
{
public static void main(String[] args)
{
long current_local_time = System.currentTimeMillis();
long long_number = 9223372036854775783L;
long long_a;
long long_b;
if (long_number < 2)
{
System.out.println(long_number + " is not a prime number");
}
else if (long_number < 4)
{
System.out.println(long_number + " is a prime number");
}
else if (long_number % 2 == 0)
{
System.out.println(long_number + " is not a prime number and is divisible by 2");
}
else
{
long_a = (long) (Math.ceil(Math.sqrt(long_number)));
terminate_loop:
{
for (long_b = 3; long_b <= long_a; long_b += 2)
{
if (long_number % long_b == 0)
{
System.out.println(long_number + " is not a prime number and is divisible by " + long_b);
break terminate_loop;
}
}
System.out.println(long_number + " is a prime number");
}
}
System.out.println("elapsed time: " + (System.currentTimeMillis() - current_local_time) + " millisecond/s");
}
}
答案 14 :(得分:0)
首先,素数从2开始。2和3是素数。素数不能被2或3整除。其余素数的形式为6k-1和6k + 1。请注意,您应该检查直到SQRT(input)的数字。这种方法非常有效。希望对您有所帮助。
public class Prime {
public static void main(String[] args) {
System.out.format("%d is prime: %s.\n", 199, isPrime(199)); // Prime
System.out.format("%d is prime: %s.\n", 198, isPrime(198)); // Not prime
System.out.format("%d is prime: %s.\n", 104729, isPrime(104729)); // Prime
System.out.format("%d is prime: %s.\n", 104727, isPrime(982443529)); // Prime
}
/**
* Tells if a number is prime or not.
*
* @param input the input
* @return If the input is prime or not
*/
private boolean isPrime(long input) {
if (input <= 1) return false; // Primes start from 2
if (input <= 3) return true; // 2 and 3 are primes
if (input % 2 == 0 || input % 3 == 0) return false; // Not prime if dividable by 2 or 3
// The rest of the primes are in the shape of 6k-1 and 6k+1
for (long i = 5; i <= Math.sqrt(input); i += 6) if (input % i == 0 || input % (i + 2) == 0) return false;
return true;
}
}
答案 15 :(得分:0)
通常,所有大于某个Primorial整数C
的质数的形式为Ck+i
的{{1}},其中i < C
和i
是整数,k
代表i
互质的数字
这里是C
的一个示例,它的运行速度比Bart Kiers对C=30
的回答要快,您可以通过计算C=6
C=210
答案 16 :(得分:0)
>>> result
280
这是什么?