Вот еще один способ:
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
.
EDIT
Обратите внимание, что isProbablePrime(certainty)
не всегда дает правильный ответ. Когда уверенность находится на низкой стороне, она дает ложные срабатывания, как @ dimo414 упомянул в комментариях.
К сожалению, я не смог найти источник, который утверждал, что isProbablePrime(certainty)
действителен для всех (32-битных) int
(при достаточной уверенности!).
Итак, я выполнил пару тестов. Я создал BitSet
размером Integer.MAX_VALUE/2
, представляющий все нечетные числа, и использовал простое сито, чтобы найти все простые числа в диапазоне 1..Integer.MAX_VALUE
. Затем я зациклился на i=1..Integer.MAX_VALUE
, чтобы проверить, что каждые new BigInteger(String.valueOf(i)).isProbablePrime(certainty) == isPrime(i)
.
Для достоверности 5 и 10 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);
}
}
который я бежал, делая:
java -Xmx1024m -cp . Main 15
Генерация простых чисел заняла ~ 30 секунд на моей машине. И фактический тест всех i
в 1..Integer.MAX_VALUE
занял около 2 часов и 15 минут.