|
|||||||
|
|
|
|||||
|
|
|||||||
Como definición, un número primo es el que sólo es divisible por sí mismo y
por 1.
Ej : 1 , 2 , 3 , 5 , 7 , 11 , 13 ...
La dificultad es determinar si un número "grande" es primo o no. Por ejemplo ¿como sabemos de
buenas a primeras si 2567 es primo? . Para ello es que se han creado variados algoritmos que
determinan la respuesta con cierta eficiencia.
Un algoritmo básico es el ir contando cuántos divisores válidos se encuentran para
un número de entrada.
En general los números primos sólo tendrían dos divisores, a excepción del 1 que obviamente
tiene un divisor. Para ello mediante un ciclo iterativo se van realizando las divisiones y
contando con una variable entera.
Algoritmo
Leer num
contador = 0
i = 1
mientras ( i <= num) hacer
si (RESTO(num / i) == 0) entonces
contador = contador + 1
fin si
i = i + 1
fin mientras
si (contador < = 2) entonces
num es primo
sino
num no es primo
fin si
Ahora para pasar este algoritmo a Java, incorporamos una variable de tipo boolean para que un método retorne true o false. El método sería el siguiente :
class prbprimo1
{
public static void main(String arg[])
{
for(int i = 1; i <= 25000; i++ )
if (primo(i) == true) System.out.println(i);
}
public static boolean primo(int num)
{
boolean p;
int contador = 0;
int i = 1;
while(i <= num)
{
if (num % i == 0) contador++;
i++;
}
if (contador <= 2) p = true;
else p = false;
return p;
}
}Bajar archivo
Mejorando un poco lo anterior, uno se da cuenta que sólo basta que el contador sea
mayor que 2 para salir del ciclo while. Esto sin duda reduce el tiempo de ejecución para los
números grandes que no sean primos, ya que con una mínima cantidad de ciclos se determina el
resultado.
Además podemos inicializar la variable p en false,
suponiendo que el número no es primo.
class prbprimo2
{
public static void main(String arg[])
{
for(int i = 1; i <= 25000; i++ )
if (primo(i) == true) System.out.println(i);
}
public static boolean primo(int num)
{
boolean p = false;
int contador = 0;
int i = 1;
while(i <= num)
{
if (num % i == 0) contador++;
i++;
if (contador > 2) i = num + 1;
}
if (contador <= 2) p = true;
return p;
}
}
Bajar archivo
Con la instrucción : if (contador > 2) i = num + 1; forzamos la salida del ciclo, logrando el resultado esperado.
Ahora, notemos que todos los números pares (menos el 2) no son primos. Además tenemos 3 números
consecutivos que son primos : 1,2,3.
Para una rápida revisión de estos números incorporamos la instrucción :
if(num < 4) p = true;
y de alguna manera no permitimos que se entre en el ciclo.
Además podemos deducir que todos los pares mayores que 2 no son primos. Esto nos llevaría
a un algoritmo como el siguiente :
Leer num
contador = 0
si(num < 4) entonces
num es primo
sino
si (RESTO(num / 2) == 0) entonces
num no es primo
sino
comprobar para los impares mayores que 3
fin si
fin si
class prbprimo3
{
public static void main(String arg[])
{
for(int i = 1; i <= 25000; i++ )
if (primo(i) == true) System.out.println(i);
}
public static boolean primo(int num)
{
boolean p = false;
if (num < 4) p = true;
else
{
if (num % 2 == 0) p = false;
else
{
int contador = 0;
int i = 1;
while(i <= num)
{
if (num % i == 0) contador++;
i++;
if (contador > 2) i = num + 1;
}
if (contador <= 2) p = true;
}
}
return p;
}
}
Bajar archivo
Como los números primos son impares , es inútil dividir num por un número par. Por lo tanto
sólo se admiten divisores impares. El problema es reducir el número de ciclos para los
impares no primos.
num : {divisores válidos}
15 : {1,3,5,7,9,11,13,15}
21 : {1,3,5,7,9,11,13,15,17,19,21}
25 : {1,3,5,7,9,11,13,15,17,19,21,23,25}
27 : {1,3,5,7,9,11,13,15,17,19,21,23,25,27}
Ahora veremos cuales son los divisores donde se produce el resto igual a cero
15 : {1,3,5,7,9,11,13,15}
21 : {1,3,5,7,9,11,13,15,17,19,21}
25 : {1,3,5,7,9,11,13,15,17,19,21,23,25}
27 : {1,3,5,7,9,11,13,15,17,19,21,23,25,27}
33 : {1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33}
Si se omite como divisor el mismo número y los divisores mayores que
(num - 1) / 2) se tiene :
15 --> (15 - 1) / 2) = 7
21 --> (21 - 1) / 2) = 10
25 --> (25 - 1) / 2) = 12
27 --> (27 - 1) / 2) = 13
33 --> (33 - 1)
/ 2)= 16
15 : {1,3,5,7}
21 : {1,3,5,7,9}
25 : {1,3,5,7,9,11}
27 : {1,3,5,7,9,11,13}
33 : {1,3,5,7,9,11,13,15}
Comprobando para los primos mayores que 3 :
5 : {1}
7 : {1,3}
11 : {1,3,5}
Para determinar el último divisor válido aplicamos el siguiente algoritmo :
limite = (num - 1) / 2
si (RESTO(limite / 2) == 0)
limite = limite - 1
fin si
Tomando en cuenta que ahora se necesita que el contador tome el valor 1 se tiene el siguiente método :
class prbprimo4
{
public static void main(String arg[])
{
for(int i = 1; i <= 25000; i++ )
if (primo(i) == true) System.out.println(i);
}
public static boolean primo(int num)
{
boolean p = false;
if (num < 4) p = true;
else
{
if (num % 2 == 0) p = false;
else
{
int contador = 0;
int i = 1;
int limite = (num - 1) / 2;
if (limite % 2 == 0) limite--;
while(i <= limite)
{
if (num % i == 0) contador++;
i += 2;
if (contador == 2) i = limite + 1;
}
if (contador == 1) p = true;
}
}
return p;
}
}
Bajar archivo
Al medir los tiempos aproximados de ejecución de cada clase, se obtuvieron los siguientes resultados (Procesador : Intel Celeron 800 MHz )
| clase | tiempo (seg) |
| prbprimo1 | 16.5 |
| prbprimo2 | 4.5 |
| prbprimo3 | 4.0 |
| prbprimo4 | 2.0 |