jueves, 1 de septiembre de 2016

VBA: Número primos en Excel

Hoy un clásico de la programación: Listar números primos.

Recordemos brevemente la definición de número primo:
Número natural mayor que 1 que tiene únicamente dos divisores distintos: él mismo y el 1.
A diferencia de los números primos, los números compuestos son los números naturales que tienen algún divisor natural aparte de sí mismos y del 1 y por lo tanto, pueden factorizarse.
El número 1, por convenio, no se considera ni primo ni compuesto.

Leer más en Wikipedia.


En el ejemplo siguiente listaremos los números primos existentes inferiores al número 200.
Insertamos en un módulo estándar de nuestro proyecto de VB:

Sub Primos()
Dim x As Integer, y As Integer
Dim contador As Integer, divisores As Integer
'un número primo es un número natural mayor que 1 que tiene únicamente dos divisores distintos:
'él mismo y el 1.

'Contador para insertar el valor en las celdas
contador = 1
contador2 = 1
'recorremos del 2 al 200
'ya que el 1 no se considera primo
For x = 2 To 200
    'reiniciamos el número de divisores de x
    divisores = 0
    For y = 2 To 200
        'si el resot del cociente es cero es que es divisor
        If (x Mod y = 0) Then
            'incrementamos el contador
            divisores = divisores + 1
        End If
    Next y
    'si hemos encontrado un solo divisor entonces es primo
    'el resto de número tendrá al menos uno (>=1)
    'en todos los casos además de por el uno!!
    If divisores = 1 Then
        'llevamos el número a la celda...
        'separándolo en dos columnas....
        '(los 24 primeros en la columna A y los siguientes en la B)
        If contador <= 24 Then
            Cells(contador, "A").Value = x
            contador = contador + 1
        Else
            Cells(contador2, "B").Value = x
            contador2 = contador2 + 1
            contador = contador + 1
        End If
    End If
Next x

End Sub

Si ejecutamos la macro veremos el resultado:

VBA: Número primos en Excel

Adicionalmente podemos construir una función UDF. Insertamos en un módulo estándar de nuestro proyecto de VB:

Function FxEsPrimo(x As Integer) As Boolean
Dim n As Integer
'En matemáticas,
'un número primo es un número natural mayor que 1 que tiene únicamente dos divisores distintos:
'él mismo y el 1.
n = 2
'damos valor VERDADERO por defecto a la función
FxEsPrimo = True
'si el número no es mayor que 1 no puede ser primo
If x <= 1 Then FxEsPrimo = False
'lanzamos un loop para ver si el número tiene algún otro divisor
Do While FxEsPrimo And n <= Sqr(x)
  'si encontramos uno
  'en cuyo caso el resto del cociente será cero
  If (x Mod n = 0) Then
    'en ese caso NO será primo
    FxEsPrimo = False
  End If
  n = n + 1
Loop

'en esta función trabajamos a la inversa,
'demostramos que no existe otro divisor para el número...
End Function

Con esta función, sobre la hoja de cálculo o en otros procedimientos, obtendremos un VERDADERO o FALSO, sobre un número entero positivo cualquiera.

4 comentarios:

  1. Hola Ismael,

    Te cambio tu macro por una fórmula de Excel, "de las de toda la vida". El número a evaluar en la celda "A2".

    =SUMAPRODUCTO(N(RESIDUO(A2;FILA(INDIRECTO("1:"&ENTERO(RAIZ(A2)))))=0))=1

    Viene a hacer lo mismo: calcula la suma de los restos resultado de dividir el número a evaluar por todos los divisores desde el 1 hasta el entero de la raíz cuadrada de dicho numero.

    Si el resultado es uno, el número en cuestión sólo es divisible por uno (y por si mismo), por lo tanto es primo y devuelve "VERDADERO". En caso contrario, no es primo y devuelve "FALSO".

    Un saludo,

    Daniel

    ResponderEliminar
    Respuestas
    1. Gracias Daniel!
      muy bueno.
      Como dices el algoritmo lógicamente es el mismo.
      Gracias de nuevo por el aporte

      Eliminar
  2. De nada Ismael, un placer.

    Si tienes algún día un rato, por curiosidad, me gustaría saber qué método es más rápido: función UDF o fórmula pura.

    Acabo de hacer una prueba con 100.000 numeros, del 1.000.000 en adelante, y sorprendentemente con la fórmula no ha tardado mucho (16 segundos).

    Daniel

    ResponderEliminar