J'essaie de trouver le moyen le plus rapide de vérifier si un nombre donné est premier ou non (en Java). Voici quelques méthodes de test de primalité que j'ai proposées. Existe-t-il un meilleur moyen que la deuxième implémentation (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 ");
}
}
}
C'est la manière la plus élégante:
public static boolean isPrime(int n) {
return !new String(new char[n]).matches(".?|(..+?)\\1+");
}
Java 1.4+. Aucune importation nécessaire.
Si court. Si belle.
Jetez un coup d’œil au test de primalité AKS (et ses diverses optimisations). C'est un test de primalité déterministe qui s'exécute en temps polynomial.
Il existe une implémentation de l'algorithme en Java de l'Université de Tuebingen (Allemagne) ici
Vous avez fait le premier pas en éliminant tous les multiples de 2.
Cependant, pourquoi vous êtes-vous arrêté là? vous auriez pu éliminer tous les multiples de 3 sauf 3, tous les multiples de 5 sauf 5, etc.
Lorsque vous suivez ce raisonnement jusqu'à sa conclusion, vous obtenez le Sieve of Eratosthenes .
Votre algorithme fonctionnera bien pour des nombres assez petits. Pour les grands nombres, des algorithmes avancés doivent être utilisés (basés par exemple sur des courbes elliptiques). Une autre idée sera d’utiliser un test "pseuso-prime". Ceux-ci testeront rapidement qu'un nombre est un nombre premier, mais ils ne sont pas précis à 100%. Cependant, ils peuvent vous aider à éliminer certains chiffres plus rapidement qu'avec votre algorithme.
Enfin, bien que le compilateur optimise probablement ceci pour vous, vous devriez écrire:
int max = (int) (Math.sqrt(n) + 1);
for (int i = 3; i <= max; i = i + 2) {
}
Si vous essayez simplement de savoir si un nombre est premier ou non, c'est assez bon, mais si vous essayez de trouver tous les nombres premiers compris entre 0 et n, une meilleure option sera le Sieve of Eratosthenes
Mais cela dépendra des limitations de Java sur la taille des tableaux, etc.
Ce que vous avez écrit correspond à ce que font les programmeurs les plus courants et devraient suffire la plupart du temps.
Cependant, si vous recherchez le "meilleur algorithme scientifique", il existe de nombreuses variantes (avec des niveaux de certitude différents) documentées http://en.wikipedia.org/wiki/Prime_number .
Par exemple, si vous avez un numéro à 70 chiffres, les limitations physiques de la machine virtuelle Java peuvent empêcher votre code de s'exécuter. Dans ce cas, vous pouvez utiliser "Sieves", etc.
Encore une fois, comme je l'ai dit s'il s'agissait d'une question de programmation ou d'une question générale d'utilisation dans un logiciel, votre code devrait être parfait :)
En fonction de la longueur du nombre à tester, vous pouvez précalculer une liste de nombres premiers pour de petites valeurs (n <10 ^ 6), qui est utilisée en premier, si le nombre demandé se situe dans cette plage. C’est bien sûr le moyen le plus rapide . Comme mentionné dans d’autres réponses, le Sieve of Eratosthenes est la méthode recommandée pour générer une liste de ce type.
Si vos nombres sont plus grands que cela, vous pouvez utiliser le test de primalité de Rabin . test de primalité de Rabin
Un test rapide dû à Jaeschke (1993) est une version déterministe du test de Miller-Rabin, qui ne présente pas de faux positifs inférieur à 4 759 123 121 et peut donc être appliqué à Java int
s.
// 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);
}
Cela ne fonctionne pas pour les variables long
, mais un test différent fonctionne: le test BPSW ne contient aucun contre-exemple allant jusqu'à 2 ^ 64. Cela consiste essentiellement en un test principal probable à 2 forts, comme ci-dessus, suivi d'un test fort à Lucas qui est un peu plus compliqué mais pas fondamentalement différent.
Ces deux tests sont beaucoup plus rapides que n'importe quel type de division d'essai.
je pense que cette méthode est la meilleure. au moins pour moi-
public static boolean isPrime(int num)
{
for (int i = 2; i<= num/i; i++)
{
if (num % i == 0)
{
return false;
}
}
return num > 1;
}
Il existe bien sûr des centaines de tests de primalité, présentant tous des avantages et des inconvénients en fonction de la taille du nombre, des formes spéciales, de la taille du facteur, etc.
Cependant, en Java, je trouve le plus utile:
BigInteger.valueOf(long/int num).isProbablePrime(int certainty);
C'est déjà implémenté et il est assez rapide (je trouve que cela prend environ 6 secondes pour une matrice 1000x1000 remplie de longs 0–2 ^ 64 et une certitude de 15) et probablement mieux optimisé que tout ce que nous pourrions imaginer.
Il utilise une version du test de primalité Baillie – PSW , qui ne contient aucun contre-exemple connu. (bien qu'il puisse utiliser une version légèrement plus faible du test, qui peut parfois se tromper. peut-être)
Efficacité de l'algorithme: O (n ^ (1/2)) Algorithme
Remarque: cet exemple de code ci-dessous contient des variables de comptage et des appels à une fonction d'impression à des fins d'impression des résultats:
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();
}
}
Lorsque le nombre premier 2147483647 est entré, la sortie suivante est générée:
23170 contrôles effectués, 2147483647 déterminé comme étant PRIME.
J'ai optimisé la division d'essai ici:.
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;
}
testé sur un système d'exploitation Intel Atom à 1,60 GHz, 2 Go de RAM et 32 bits
résultat du test:
Le plus grand nombre premier sous Long.MAX_VALUE = 9223372036854775807 vaut 9223372036854775783
le temps écoulé est de 171499 millisecondes ou 2 minutes et 51 secondes
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");
}
}