jueves, 1 de julio de 2010

Numeros primos en Java

Los números primos a lo largo del tiempo ha sido una de las ramas más complejas de la matemática. Poseen muchas aplicaciones prácticas debido a sus propiedades de números verdaderamente "únicos", asi como es el caso de la criptografía asimétrica por ejemplo. Pero uno de los problemas que ha tenido la humanidad desde sus inicios es determinar una función eficiente que genere estos números con un bajo costo computacional. Aqui escribo 5 versiones de funciones para cálcular números primos, en orden de rapidez y con un algoritmo que se encarga de medir el tiempo de ejecucion para numeros relativamente grandes.


public class Main {
private static long tiempomin=0;
private static int ganador = -1;

public static class Cronometro {
long t0;
public Cronometro() {
t0 = System.currentTimeMillis();
}
public long Parar() {
return (System.currentTimeMillis()-t0);
}
}

public static boolean esPrimo1(long n) {
if(n < 2) return false;
if(n < 4) return true;
for (long i = 2; i <= n; i++) if (n%i == 0) return false;
return true;
}

public static boolean esPrimo2(long n) {
if(n < 2) return false;
if(n < 4) return true;
for (long i = 2; i <= (long) Math.sqrt(n); i++) if (n%i == 0) return false;
return true;
}

public static boolean esPrimo3(long n) {
if(n< 2) return false;
if(n< 4) return true;
for (long i = 2; i*i <= n; i++) if (n%i == 0) return false;
return true;
}

public static boolean esPrimo4(long n) {
long nPrueba;
long nLimite;
if(n%2==0) return false;
nPrueba = 3;
nLimite = n;
while(nLimite > nPrueba) {
if(n%nPrueba==0) return false;
nLimite = n/nPrueba;
nPrueba += 2;
}
return true;
}

public static void Invocar(int nFuncion, long max) {
long enc=0;
if(ganador< 0) System.out.println("Se inicia el conteo para n=" + max + "...");
Cronometro reloj = new Cronometro();
long t2=0;
switch(nFuncion) {
case 1: for(long i=0; i <= max; i++) if(esPrimo1(i)) enc++; break;
case 2: for(long i=0; i <= max; i++) if(esPrimo2(i)) enc++; break;
case 3: for(long i=0; i <= max; i++) if(esPrimo3(i)) enc++; break;
case 4: for(long i=0; i <= max; i++) if(esPrimo4(i)) enc++; break;
}
t2 = reloj.Parar();
if(tiempomin==0 || t2< tiempomin) { tiempomin = t2; ganador = nFuncion; }
System.out.println("esPrimo" + nFuncion + "(1..n) " + t2 + " ms (" + enc + " numeros primos encontrados)");
}

public static void main(String[] args) {
int nfunciones = 4;
long maximo = 6000000;
for(int i=2; i <= nfunciones; i++) Invocar(i,maximo);
System.out.println("La funcion ganadora es esPrimo" + ganador + "() con " + tiempomin + " ms!!");
}

}

1 comentario:

Unknown dijo...

Por cierto, la función número 4 puede calcular facilmente los numeros entre 1 y 6.000.000 en menos de 12 segundos.

Se inicia el conteo para n=6000000...
esPrimo2(1..n) 34294 ms (412849 numeros primos encontrados)
esPrimo3(1..n) 13424 ms (412849 numeros primos encontrados)
esPrimo4(1..n) 11735 ms (412849 numeros primos encontrados)
La funcion ganadora es esPrimo4() con 11735 ms!!