¿Cómo crear el mapeo más compacto n → isprime (n) hasta un límite N?


152

Naturalmente, porque bool isprime(number)habría una estructura de datos que podría consultar.
Yo defino el mejor algoritmo , que es el algoritmo que produce una estructura de datos con el consumo de memoria más baja para el rango (1, N], donde N es una constante.
Sólo un ejemplo de lo que estoy buscando: Podría representar cada número impar con un bit, por ejemplo, para el rango de números dado (1, 10], comienza en 3:1110

El siguiente diccionario se puede exprimir más, ¿verdad? Podría eliminar múltiplos de cinco con algo de trabajo, pero los números que terminan con 1, 3, 7 o 9 deben estar allí en la matriz de bits.

¿Cómo resuelvo el problema?


3
Su solicitud es un poco vaga. Usted proporciona una firma que prueba un número único, pero luego solicita una estructura de datos de (1, N]. ¿Desea un algoritmo que genere un diccionario <int, bool> o simplemente una función de una sola vez que verifica si un solo número es primo?
Michael Haren

@Michael Lo siento, esa es la mejor descripción que se me ocurrió. Lo que estoy buscando es exactamente como usted dice: un diccionario booleano. Me gustaría minimizar el espacio del diccionario. Gracias :)
AraK

1
Si eso es lo que está buscando, ya se ha preguntado: stackoverflow.com/questions/1032427/…
Ben S

14
Tendrías que preguntarle a la NSA
Charles Bretana el

Respuestas:


79

Hay muchas formas de hacer la prueba de primalidad .

Realmente no hay una estructura de datos para consultar. Si tiene muchos números para probar, probablemente debería ejecutar una prueba probabilística, ya que son más rápidos, y luego seguir con una prueba determinista para asegurarse de que el número sea primo.

Debe saber que la matemática detrás de los algoritmos más rápidos no es para los débiles de corazón.


44
Miller-Rabin es una prueba probabilística rápida popular para comenzar.
qwr

214

El algoritmo más rápido para pruebas principales generales es AKS . El artículo de Wikipedia lo describe en detalle y enlaces al documento original.

Si desea encontrar números grandes, busque números primos que tengan formas especiales como números primos de Mersenne .

El algoritmo que suelo implementar (fácil de entender y codificar) es el siguiente (en Python):

def isprime(n):
    """Returns True if n is prime."""
    if n == 2:
        return True
    if n == 3:
        return True
    if n % 2 == 0:
        return False
    if n % 3 == 0:
        return False

    i = 5
    w = 2

    while i * i <= n:
        if n % i == 0:
            return False

        i += w
        w = 6 - w

    return True

Es una variante del O(sqrt(N))algoritmo clásico . Utiliza el hecho de que un primo (excepto 2 y 3) tiene forma 6k - 1o 6k + 1solo mira a los divisores de esta forma.

A veces, si realmente quiero velocidad y el rango es limitado , implemento una prueba pseudoprime basada en el pequeño teorema de Fermat . Si realmente quiero más velocidad (es decir, evito el algoritmo O (sqrt (N)) por completo), precalculo los falsos positivos (vea los números de Carmichael ) y hago una búsqueda binaria. Esta es la prueba más rápida que he implementado, el único inconveniente es que el rango es limitado.


77
Dos preguntas: ¿Puede explicar mejor lo que las variables iy wson, y lo que se entiende por la forma 6k-1y 6k+1? Gracias por su comprensión y el ejemplo de código (que estoy tratando de entender)
Freedom_Ben

66
@Freedom_Ben Aquí tienes, quora.com/…
Alan Dong

66
¿No sería mejor calcular el sqrtde nuna vez y compararlo i, en lugar de calcular i * icada ciclo del ciclo?
pedros

3
@Dschoni ... ¿pero no puedes incluir la implementación más rápida en los campos de comentarios aquí para compartir con nosotros?
GreenAsJade

3
Falla para el número 1 :(
Damjan Pavlica

27

El mejor método, en mi opinión, es usar lo que se ha ido antes.

Hay listas de los primeros Nnúmeros primos en Internet con una Nextensión de al menos cincuenta millones . Descarga los archivos y úsalos, es probable que sea mucho más rápido que cualquier otro método que se te ocurra.

Si desea un algoritmo real para hacer sus propios números primos, Wikipedia tiene todo tipo de cosas buenas sobre números primos aquí , incluidos enlaces a los diversos métodos para hacerlo y pruebas principales aquí , tanto métodos basados ​​en probabilidad como métodos deterministas rápidos.

Debería haber un esfuerzo concertado para encontrar los primeros mil millones (o incluso más) primos y publicarlos en la red en algún lugar para que la gente pueda dejar de hacer este mismo trabajo una y otra vez y ... :-)


2
@hamedbh: Interesante. ¿Has intentado descargar esos archivos? Parece que no existen.
paxdiablo

Todavía no, me temo: solo estaba mirando rápidamente durante mi almuerzo. Eliminaré ese enlace en caso de que haya algo malicioso al respecto. Lo siento, realmente debería haberlo comprobado primero.
Hamed

1
Dichas listas hacen existir. Los he visto hace años, pero nunca me importó descargarlos. La verdad es que ocupan mucho espacio (relativamente hablando) y no deben incluirse en los programas que uno vende o distribuye. Además, siempre y para siempre estarán incompletos. Tiene más sentido probar cada número que aparece en la práctica durante el uso de un programa, ya que se probarán muchos menos de esa manera que la longitud de cualquier lista que pueda tener. Además, creo que pax no se da cuenta de que el propósito de los algoritmos primarios, la mayoría de las veces, es probar la eficiencia / velocidad en lugar de encontrar primos.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, acepta que la lista de todos los números primos estará desactualizada para siempre, ya que he visto la prueba matemática de que son infinitos en número. Sin embargo, la lista de los primeros xnúmeros primos será poco probable que sea incompleta una vez construido :-)
paxdiablo

1
Es cierto, pero hay mejores métodos de almacenamiento que leer un archivo de forma lineal. Si realmente desea leer de un conjunto almacenado de primos pregenerados, pruebe con una estructura de datos más complicada que acelere el problema.
CogitoErgoCogitoSum

10
bool isPrime(int n)
{
    // Corner cases
    if (n <= 1)  return false;
    if (n <= 3)  return true;

    // This is checked so that we can skip 
    // middle five numbers in below loop
    if (n%2 == 0 || n%3 == 0) return false;

    for (int i=5; i*i<=n; i=i+6)
        if (n%i == 0 || n%(i+2) == 0)
           return false;

    return true;
}

esto es solo la implementación en C ++ del algoritmo AKS anterior


1
Es uno de los algoritmos deterministas más eficientes que he encontrado, sí, pero no es una implementación de AKS. El sistema AKS es mucho más nuevo que el algoritmo descrito. Podría decirse que es más eficiente, pero es algo difícil de implementar, debido a factores factoriales / coeficientes binomiales potencialmente astronómicamente grandes.
CogitoErgoCogitoSum

¿Cómo es esto diferente de la respuesta (no) de Derri Leahi (que no sea ​​C en lugar de Java)? ¿Cómo responde esto What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]?
barba gris

1
¿Cómo (n% i == 0 || n% (i + 2) == 0) corresponde a 6n + 1 y 6n-1?

@YeshwanthVenkatesh: How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?parte de la respuesta son diferentes roles para n, el otro es 6n + 1 y 6n-1 equivalente a (6n-1) +0 y (6n-1) + 2 *.
barba gris

También tenga en cuenta que este algoritmo no da el resultado correcto para 5y 7.
Athan Clark

7

Comparé la eficiencia de las sugerencias más populares para determinar si un número es primo. He utilizado python 3.6en ubuntu 17.10; Probé con números de hasta 100,000 (puedes probar con números más grandes usando mi código a continuación).

Esta primera gráfica compara las funciones (que se explican más adelante en mi respuesta), mostrando que las últimas funciones no crecen tan rápido como la primera al aumentar los números.

trama1

Y en el segundo gráfico podemos ver que en el caso de los números primos, el tiempo crece de manera constante, pero los números no primos no crecen tan rápido en el tiempo (porque la mayoría de ellos se pueden eliminar desde el principio).

plot2

Aquí están las funciones que utilicé:

  1. Esta respuesta y esta respuesta sugirieron una construcción usando all():

    def is_prime_1(n):
        return n > 1 and all(n % i for i in range(2, int(math.sqrt(n)) + 1))
    
  2. Esta respuesta utilizó algún tipo de ciclo while:

    def is_prime_2(n):
        if n <= 1:
            return False
        if n == 2:
            return True
        if n == 3:
            return True
        if n % 2 == 0:
            return False
        if n % 3 == 0:
            return False
    
        i = 5
        w = 2
        while i * i <= n:
            if n % i == 0:
                return False
            i += w
            w = 6 - w
    
        return True
    
  3. Esta respuesta incluía una versión con un forbucle:

    def is_prime_3(n):
        if n <= 1:
            return False
    
        if n % 2 == 0 and n > 2:
            return False
    
        for i in range(3, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    
  4. Y mezclé algunas ideas de las otras respuestas en una nueva:

    def is_prime_4(n):
        if n <= 1:          # negative numbers, 0 or 1
            return False
        if n <= 3:          # 2 and 3
            return True
        if n % 2 == 0 or n % 3 == 0:
            return False
    
        for i in range(5, int(math.sqrt(n)) + 1, 2):
            if n % i == 0:
                return False
    
        return True
    

Aquí está mi script para comparar las variantes:

import math
import pandas as pd
import seaborn as sns
import time
from matplotlib import pyplot as plt


def is_prime_1(n):
    ...
def is_prime_2(n):
    ...
def is_prime_3(n):
    ...
def is_prime_4(n):
    ...

default_func_list = (is_prime_1, is_prime_2, is_prime_3, is_prime_4)

def assert_equal_results(func_list=default_func_list, n):
    for i in range(-2, n):
        r_list = [f(i) for f in func_list]
        if not all(r == r_list[0] for r in r_list):
            print(i, r_list)
            raise ValueError
    print('all functions return the same results for integers up to {}'.format(n))

def compare_functions(func_list=default_func_list, n):
    result_list = []
    n_measurements = 3

    for f in func_list:
        for i in range(1, n + 1):
            ret_list = []
            t_sum = 0
            for _ in range(n_measurements):
                t_start = time.perf_counter()
                is_prime = f(i)
                t_end = time.perf_counter()

                ret_list.append(is_prime)
                t_sum += (t_end - t_start)

            is_prime = ret_list[0]
            assert all(ret == is_prime for ret in ret_list)
            result_list.append((f.__name__, i, is_prime, t_sum / n_measurements))

    df = pd.DataFrame(
        data=result_list,
        columns=['f', 'number', 'is_prime', 't_seconds'])
    df['t_micro_seconds'] = df['t_seconds'].map(lambda x: round(x * 10**6, 2))
    print('df.shape:', df.shape)

    print()
    print('', '-' * 41)
    print('| {:11s} | {:11s} | {:11s} |'.format(
        'is_prime', 'count', 'percent'))
    df_sub1 = df[df['f'] == 'is_prime_1']
    print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
        'all', df_sub1.shape[0], 100))
    for (is_prime, count) in df_sub1['is_prime'].value_counts().iteritems():
        print('| {:11s} | {:11,d} | {:9.1f} % |'.format(
            str(is_prime), count, count * 100 / df_sub1.shape[0]))
    print('', '-' * 41)

    print()
    print('', '-' * 69)
    print('| {:11s} | {:11s} | {:11s} | {:11s} | {:11s} |'.format(
        'f', 'is_prime', 't min (us)', 't mean (us)', 't max (us)'))
    for f, df_sub1 in df.groupby(['f', ]):
        col = df_sub1['t_micro_seconds']
        print('|{0}|{0}|{0}|{0}|{0}|'.format('-' * 13))
        print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
            f, 'all', col.min(), col.mean(), col.max()))
        for is_prime, df_sub2 in df_sub1.groupby(['is_prime', ]):
            col = df_sub2['t_micro_seconds']
            print('| {:11s} | {:11s} | {:11.2f} | {:11.2f} | {:11.2f} |'.format(
                f, str(is_prime), col.min(), col.mean(), col.max()))
    print('', '-' * 69)

    return df

Al ejecutar la función compare_functions(n=10**5)(números hasta 100.000) obtengo esta salida:

df.shape: (400000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |     100,000 |     100.0 % |
| False       |      90,408 |      90.4 % |
| True        |       9,592 |       9.6 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.57 |        2.50 |      154.35 |
| is_prime_1  | False       |        0.57 |        1.52 |      154.35 |
| is_prime_1  | True        |        0.89 |       11.66 |       55.54 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        1.14 |      304.82 |
| is_prime_2  | False       |        0.24 |        0.56 |      304.82 |
| is_prime_2  | True        |        0.25 |        6.67 |       48.49 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        0.95 |       50.99 |
| is_prime_3  | False       |        0.20 |        0.60 |       40.62 |
| is_prime_3  | True        |        0.58 |        4.22 |       50.99 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.20 |        0.89 |       20.09 |
| is_prime_4  | False       |        0.21 |        0.53 |       14.63 |
| is_prime_4  | True        |        0.20 |        4.27 |       20.09 |
 ---------------------------------------------------------------------

Luego, ejecutando la función compare_functions(n=10**6)(números hasta 1,000,000) obtengo esta salida:

df.shape: (4000000, 5)

 -----------------------------------------
| is_prime    | count       | percent     |
| all         |   1,000,000 |     100.0 % |
| False       |     921,502 |      92.2 % |
| True        |      78,498 |       7.8 % |
 -----------------------------------------

 ---------------------------------------------------------------------
| f           | is_prime    | t min (us)  | t mean (us) | t max (us)  |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_1  | all         |        0.51 |        5.39 |     1414.87 |
| is_prime_1  | False       |        0.51 |        2.19 |      413.42 |
| is_prime_1  | True        |        0.87 |       42.98 |     1414.87 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_2  | all         |        0.24 |        2.65 |      612.69 |
| is_prime_2  | False       |        0.24 |        0.89 |      322.81 |
| is_prime_2  | True        |        0.24 |       23.27 |      612.69 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_3  | all         |        0.20 |        1.93 |       67.40 |
| is_prime_3  | False       |        0.20 |        0.82 |       61.39 |
| is_prime_3  | True        |        0.59 |       14.97 |       67.40 |
|-------------|-------------|-------------|-------------|-------------|
| is_prime_4  | all         |        0.18 |        1.88 |      332.13 |
| is_prime_4  | False       |        0.20 |        0.74 |      311.94 |
| is_prime_4  | True        |        0.18 |       15.23 |      332.13 |
 ---------------------------------------------------------------------

Usé el siguiente script para trazar los resultados:

def plot_1(func_list=default_func_list, n):
    df_orig = compare_functions(func_list=func_list, n=n)
    df_filtered = df_orig[df_orig['t_micro_seconds'] <= 20]
    sns.lmplot(
        data=df_filtered, x='number', y='t_micro_seconds',
        col='f',
        # row='is_prime',
        markers='.',
        ci=None)

    plt.ticklabel_format(style='sci', axis='x', scilimits=(3, 3))
    plt.show()


6

Uno puede usar sympy .

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

De documentos sympy. El primer paso es buscar factores triviales, que si se encuentran permiten un retorno rápido. A continuación, si el tamiz es lo suficientemente grande, utilice la búsqueda de bisección en el tamiz. Para números pequeños, se realiza un conjunto de pruebas deterministas de Miller-Rabin con bases que se sabe que no tienen contraejemplos en su rango. Finalmente, si el número es mayor que 2 ^ 64, se realiza una prueba BPSW fuerte. Si bien esta es una prueba principal probable y creemos que existen contraejemplos, no hay contraejemplos conocidos


Un algoritmo es una secuencia de pasos bien definidos que define una solución abstracta a un problema. - ¿ Cuál es la secuencia concebible de pasos en el código presentado? ¿Cuál es su memory consumption?
barba gris

2
@anciano. De documentos sympy. El primer paso es buscar factores triviales, que si se encuentran permiten un retorno rápido. A continuación, si el tamiz es lo suficientemente grande, utilice la búsqueda de bisección en el tamiz. Para números pequeños, se realiza un conjunto de pruebas deterministas de Miller-Rabin con bases que se sabe que no tienen contraejemplos en su rango. Finalmente, si el número es mayor que 2 ^ 64, se realiza una prueba BPSW fuerte. Si bien esta es una prueba principal probable y creemos que existen contraejemplos, no hay contraejemplos conocidos.
LetzerWille

6

En Python 3:

def is_prime(a):
    if a < 2:
        return False
    elif a!=2 and a % 2 == 0:
        return False
    else:
        return all (a % i for i in range(3, int(a**0.5)+1))

Explicación: Un número primo es un número solo divisible por sí mismo y 1. Ej: 2,3,5,7 ...

1) si a <2: si "a" es menor que 2, no es primo.

2) elif a! = 2 y a% 2 == 0: si "a" es divisible por 2, definitivamente no es primo. Pero si a = 2 no queremos evaluar eso, ya que es un número primo. De ahí la condición a! = 2

3) devuelve todo (a% i para i en rango (3, int (a 0.5) +1)): ** Primero mira lo que hace el comando all () en python. A partir de 3 dividimos "a" hasta su raíz cuadrada (a ** 0.5). Si "a" es divisible, la salida será False. ¿Por qué raíz cuadrada? Digamos a = 16. La raíz cuadrada de 16 = 4. No necesitamos evaluar hasta 15. Solo necesitamos verificar hasta 4 para decir que no es primo.

Extra: Un ciclo para encontrar todos los números primos dentro de un rango.

for i in range(1,100):
    if is_prime(i):
        print("{} is a prime number".format(i))

1
¿Cómo difiere esto de la respuesta de Oleksandr Shmyheliuk ? (Ambos pierden un "paso 2" en range()...)
barba gris

1
Si un número es par, entonces no es primo (excluyendo 2). Por lo tanto, no es necesario verificar los números pares. Esto será mucho más rápido si desea obtener un número primo dentro de un rango. Directamente excluirá los números pares.
Crecimiento profundo


3

Para números grandes, no puede simplemente verificar ingenuamente si el número candidato N es divisible por ninguno de los números menores que sqrt (N). Hay pruebas mucho más escalables disponibles, como la prueba de primalidad de Miller-Rabin . A continuación tienes implementación en python:

def is_prime(x):
    """Fast implementation fo Miller-Rabin primality test, guaranteed to be correct."""
    import math
    def get_sd(x):
        """Returns (s: int, d: int) for which x = d*2^s """
        if not x: return 0, 0
        s = 0
        while 1:
            if x % 2 == 0:
                x /= 2
                s += 1
            else:
                return s, x
    if x <= 2:
        return x == 2
    # x - 1 = d*2^s
    s, d = get_sd(x - 1)
    if not s:
        return False  # divisible by 2!
    log2x = int(math.log(x) / math.log(2)) + 1
    # As long as Riemann hypothesis holds true, it is impossible
    # that all the numbers below this threshold are strong liars.
    # Hence the number is guaranteed to be a prime if no contradiction is found.
    threshold = min(x, 2*log2x*log2x+1)
    for a in range(2, threshold):
        # From Fermat's little theorem if x is a prime then a^(x-1) % x == 1
        # Hence the below must hold true if x is indeed a prime:
        if pow(a, d, x) != 1:
            for r in range(0, s):
                if -pow(a, d*2**r, x) % x == 1:
                    break
            else:
                # Contradicts Fermat's little theorem, hence not a prime.
                return False
    # No contradiction found, hence x must be a prime.
    return True

Puedes usarlo para encontrar números primos enormes:

x = 10000000000000000000000000000000000000000000000000000000000000000000000000000
for e in range(1000):
    if is_prime(x + e):
        print('%d is a prime!' % (x + e))
        break

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Si está probando enteros aleatorios, probablemente desee probar primero si el número candidato es divisible por alguno de los números primos menores que, digamos 1000, antes de llamar a Miller-Rabin. Esto lo ayudará a filtrar obvios no primos como 10444344345.


Esta es la prueba de Miller. La prueba de Miller-Rabin es la versión probabilística en la que se prueban bases seleccionadas al azar hasta que se alcanza la confianza suficiente. Además, la prueba de Miller no depende directamente de la Hipótesis de Riemann, sino de la Hipótesis de Riemann Generalizada (GRH) para los caracteres de Diriclet cuadráticos (sé que es un bocado, y tampoco lo entiendo). Lo que significa que una prueba potencial para la Hipótesis de Riemann puede que ni siquiera se aplique al GRH y, por lo tanto, no pruebe que la prueba de Miller sea correcta. Un caso aún peor sería, por supuesto, si el GRH es refutado.
Arne Vogel

2

Demasiado tarde para la fiesta, pero espero que esto ayude. Esto es relevante si está buscando grandes números primos:

Para probar números impares grandes, debe usar la prueba de Fermat y / o la prueba de Miller-Rabin.

Estas pruebas usan exponenciación modular que es bastante costosa, para nexponenciación de bits necesita al menos nuna multiplicación int grande yn int grande una división int grande. Lo que significa que la complejidad de la exponenciación modular es O (n³).

Entonces, antes de usar las armas grandes, debes hacer bastantes divisiones de prueba. Pero no lo hagas ingenuamente, hay una manera de hacerlo rápido. Primero multiplique tantos números primos juntos como corresponda en las palabras que usa para los enteros grandes. Si usa palabras de 32 bits, multiplique 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 y calcule el máximo común divisor con el número que prueba usando el algoritmo euclidiano. Después del primer paso, el número se reduce por debajo del tamaño de la palabra y continúa el algoritmo sin realizar divisiones enteras grandes. Si el MCD! = 1, eso significa que uno de los números primos que multiplicó juntos divide el número, por lo que tiene una prueba de que no es primo. Luego continúe con 31 * 37 * 41 * 43 * 47 = 95041567, y así sucesivamente.

Una vez que haya probado varios cientos (o mil) primos de esta manera, puede hacer 40 rondas de la prueba de Miller-Rabin para confirmar que el número es primo, después de 40 rondas puede estar seguro de que el número es primo, solo hay 2 ^ -80 posibilidades de que sea no (es más probable que su hardware funcione mal ...).


1

Tengo una función principal que funciona hasta (2 ^ 61) -1 Aquí:

from math import sqrt
def isprime(num): num > 1 and return all(num % x for x in range(2, int(sqrt(num)+1)))

Explicación:

La all()función se puede redefinir para esto:

def all(variables):
    for element in variables:
        if not element: return False
    return True

La all()función solo pasa por una serie de bools / números y regresaFalse si ve 0 o False.

La sqrt()función solo está haciendo raíz cuadrada de un número.

Por ejemplo:

>>> from math import sqrt
>>> sqrt(9)
>>> 3
>>> sqrt(100)
>>> 10

La num % xparte devuelve el resto de num / x.

Finalmente, range(2, int(sqrt(num)))significa que creará una lista que comienza en 2 y termina enint(sqrt(num)+1)

Para obtener más información sobre el rango, eche un vistazo a este sitio web .

La num > 1parte solo está verificando si la variablenum es mayor que 1, porque 1 y 0 no se consideran números primos.

Espero que esto haya ayudado :)


Por favor discuta cómo se trata de the bestalgoritmo, o incluso uno bueno .
barba gris

@greybeard, la mayoría de las funciones primas aquí no van a (2 ^ 31) -1 o tardan demasiado en números altos, pero la mía funciona hasta (2 ^ 61) -1, por lo que puede verificar si un número es primo con un número más amplio rango de números.
WhyAreYouReadingThis

1

En Python:

def is_prime(n):
    return not any(n % p == 0 for p in range(2, int(math.sqrt(n)) + 1))

Una conversión más directa del formalismo matemático a Python usaría todo (n% p! = 0 ...) , pero eso requiere una evaluación estricta de todos los valores de p. La no versión puede terminar antes si se encuentra un valor Verdadero.


Wrt "all (n% p! = 0 ...), pero eso requiere una evaluación estricta de todos los valores de p" , eso es incorrecto. anyy allambos saldrán temprano . Entonces en el primero pdonde n % pestá 0, allsaldría.
Aneroide

1

mejor algoritmo para el número de Primes javascript

 function isPrime(num) {
      if (num <= 1) return false;
      else if (num <= 3) return true;
      else if (num % 2 == 0 || num % 3 == 0) return false;
      var i = 5;
      while (i * i <= num) {
        if (num % i == 0 || num % (i + 2) == 0) return false;
        i += 6;
      }
      return true
    }

1
import math
import time


def check_prime(n):

    if n == 1:
        return False

    if n == 2:
        return True

    if n % 2 == 0:
        return False

    from_i = 3
    to_i = math.sqrt(n) + 1

    for i in range(from_i, int(to_i), 2):
        if n % i == 0:
            return False
    return True

1

Un número primo es cualquier número que solo es divisible por 1 y en sí mismo. Todos los demás números se llaman compuestos .

La forma más simple de encontrar un número primo es verificar si el número de entrada es un número compuesto:

    function isPrime(number) {
        // Check if a number is composite
        for (let i = 2; i < number; i++) {
            if (number % i === 0) {
                return false;
            }
        }
        // Return true for prime numbers
        return true;
    }

El programa tiene que dividir el valor de numberentre todos los números enteros de 1 y hasta su valor. Si este número se puede dividir equitativamente, no solo entre uno y sí mismo, es un número compuesto.

El valor inicial de la variable itiene que ser 2 porque los números primos y compuestos pueden dividirse equitativamente entre 1.

    for (let i = 2; i < number; i++)

Entonces ies menor que numberpor la misma razón. Tanto los números primos como los compuestos se pueden dividir equitativamente por sí mismos. Por lo tanto, no hay razón para verificarlo.

Luego verificamos si la variable se puede dividir equitativamente utilizando el operador restante.

    if (number % i === 0) {
        return false;
    }

Si el resto es cero, significa que numberse puede dividir equitativamente, por lo tanto, es un número compuesto y devuelve falso.

Si el número ingresado no cumplió con la condición, significa que es un número primo y la función devuelve verdadero.


1
(Si bien creo que simplestuna interpretación válida de los mejores :) La pregunta es ¿Cuál es el mejor algoritmo para verificar si un número es primo? : ¿Verificando la divisibilidad es number / 2 < i < numberventajoso? ¿Qué hay de number < i*i? ¿Qué dicen los entendibles de las otras 3³ respuestas?
barba gris

1

Déjame sugerirte la solución perfecta para enteros de 64 bits. Lamento usar C #. Aún no lo ha especificado como python en su primera publicación. Espero que pueda encontrar una función modPow simple y analizarla fácilmente.

public static bool IsPrime(ulong number)
{
    return number == 2 
        ? true 
        : (BigInterger.ModPow(2, number, number) == 2 
            ? (number & 1 != 0 && BinarySearchInA001567(number) == false) 
            : false)
}

public static bool BinarySearchInA001567(ulong number)
{
    // Is number in list?
    // todo: Binary Search in A001567 (https://oeis.org/A001567) below 2 ^ 64
    // Only 2.35 Gigabytes as a text file http://www.cecm.sfu.ca/Pseudoprimes/index-2-to-64.html
}

1
bool isPrime(int n) {
if(n <= 3)
    return (n > 1)==0? false: true;
else if(n%2 == 0 || n%3 == 0)
    return false;

int i = 5;

while(i * i <= n){
    if(n%i == 0 || (n%(i+2) == 0))
        return false;
    i = i + 6;
}

return true;
}

para cualquier número, las iteraciones mínimas para verificar si el número es primo o no puede ser de 2 a raíz cuadrada del número. Para reducir aún más las iteraciones, podemos verificar si el número es divisible por 2 o 3, ya que los números máximos pueden eliminarse verificando si el número es divisible por 2 o 3. Además, cualquier número primo mayor que 3 puede expresarse como 6k +1 o 6k-1. Entonces la iteración puede ir de 6k + 1 a la raíz cuadrada del número.


1
Sería mejor si agregara alguna explicación a su respuesta usando edit . Puede que no esté claro para muchos lectores por qué su respuesta es buena, y podrían aprender de usted si explica más.
Brian Tompsett - 汤 莱恩

0

¿El recuerdo más pequeño? Esto no es el más pequeño, pero es un paso en la dirección correcta.

class PrimeDictionary {
    BitArray bits;

    public PrimeDictionary(int n) {
        bits = new BitArray(n + 1);
        for (int i = 0; 2 * i + 3 <= n; i++) {
            bits.Set(i, CheckPrimality(2 * i + 3));
        }
    }

    public PrimeDictionary(IEnumerable<int> primes) {
        bits = new BitArray(primes.Max());
        foreach(var prime in primes.Where(p => p != 2)) {
            bits.Set((prime - 3) / 2, true);
        }
    }

    public bool IsPrime(int k) {
        if (k == 2) {
            return true;
        }
        if (k % 2 == 0) {
            return false;
        }
        return bits[(k - 3) / 2];
    }
}

Por supuesto, debe especificar la definición de CheckPrimality.


0

Creo que uno de los más rápidos es mi método que hice.

void prime(long long int number) {
    // Establishing Variables
    long long int i = 5;
    int w = 2;
    const long long int lim = sqrt(number);

    // Gets 2 and 3 out of the way
    if (number == 1) { cout << number << " is hard to classify. \n";  return; }
    if (number == 2) { cout << number << " is Prime. \n";  return; }
    if (number == 3) { cout << number << " is Prime. \n";  return; }

    // Tests Odd Ball Factors
    if (number % 2 == 0) { cout << number << " is not Prime. \n";  return; }
    if (number % 3 == 0) { cout << number << " is not Prime. \n";  return; }

    while (i <= lim) {
        if (number % i == 0) { cout << number << " is not Prime. \n";  return; }
        // Tests Number
        i = i + w; // Increments number
        w = 6 - i; // We already tested 2 and 3
        // So this removes testing multepules of this
    }
    cout << number << " is Prime. \n"; return;
}

1
un error puede ser ... 6 - i?
Hmmm

0

Idea similar al algoritmo AKS que se ha mencionado

public static boolean isPrime(int n) {

    if(n == 2 || n == 3) return true;
    if((n & 1 ) == 0 || n % 3 == 0) return false;
    int limit = (int)Math.sqrt(n) + 1;
    for(int i = 5, w = 2; i <= limit; i += w, w = 6 - w) {
        if(n % i == 0) return false;
        numChecks++;
    }
    return true;
}

1
Sin relación con el algoritmo AKS .
barba gris

En el bucle for no necesita marcar "i <= limit", es suficiente marcar "i <limit". Entonces, en cada iteración, haces una comparación menos.
Andrushenko Alexander

0

Para averiguar si el número o los números en un rango son / son primos.

#!usr/bin/python3

def prime_check(*args):
    for arg in args:
        if arg > 1:     # prime numbers are greater than 1
            for i in range(2,arg):   # check for factors
                if(arg % i) == 0:
                    print(arg,"is not Prime")
                    print(i,"times",arg//i,"is",arg)
                    break
            else:
                print(arg,"is Prime")
                
            # if input number is less than
            # or equal to 1, it is not prime
        else:
            print(arg,"is not Prime")
    return
    
# Calling Now
prime_check(*list(range(101)))  # This will check all the numbers in range 0 to 100 
prime_check(#anynumber)         # Put any number while calling it will check.

Ejecute este código, funcionará tanto para una lista como para un número particular
Harsh Singh el

0
myInp=int(input("Enter a number: "))
if myInp==1:
    print("The number {} is neither a prime not composite no".format(myInp))
elif myInp>1:
    for i in range(2,myInp//2+1):
        if myInp%i==0:
            print("The Number {} is not a prime no".format(myInp))
            print("Because",i,"times",myInp//i,"is",myInp)
            break
    else:
        print("The Number {} is a prime no".format(myInp))
else:
    print("Alas the no {} is a not a prime no".format(myInp))

1
Cuando escribe una respuesta, incluso si es correcta, también escriba un poco explicando lo que está haciendo y por qué. De esta manera, las personas que leen su respuesta pueden comprender más fácilmente lo que ha resuelto. ¡Gracias!
kim

1
Claro Kim, gracias por señalarlo. Este es mi primer programa en Stackoverflow, de ahora en adelante agregaré los comentarios y explicaciones correspondientes.
DKB

0
public static boolean isPrime(int number) {
 if(number < 2)
   return false;
 else if(number == 2 || number == 3)
        return true;
      else {
        for(int i=2;i<=number/2;i++)
           if(number%i == 0)
             return false;
           else if(i==number/2)
                return true;
      }
    return false;
}

0

Podrías probar algo como esto.

def main():
    try:
        user_in = int(input("Enter a number to determine whether the number is prime or not: "))
    except ValueError:
        print()
        print("You must enter a number!")
        print()
        return
    list_range = list(range(2,user_in+1))
    divisor_list = []
    for number in list_range:
        if user_in%number==0:
            divisor_list.append(number)
    if len(divisor_list) < 2:
        print(user_in, "is a prime number!")
        return
    else:
        print(user_in, "is not a prime number!")
        return
main()

Esta es una solución terrible para probar la primacía. Una vez que encuentre un divisor, sabrá la respuesta, ¡pero este código encuentra todos los divisores y luego decide! E ignora la solicitud del OP de un predicado booleano, ya que siempre regresa None.
cdlane

@cdlane Sé que esto no es una función de retorno booleana, todavía soy un principiante en Python y sé que no es perfecto, gracias por comentar de todos modos
Patrick Jane

0

La mayoría de las respuestas anteriores son correctas, pero aquí hay una forma más de probar para ver que un número es número primo. Como recordatorio, los números primos son números enteros mayores que 1 cuyos únicos factores son 1 y en sí mismos ( fuente )

Solución:

Por lo general, puede crear un bucle y comenzar a probar su número para ver si es divisible por 1,2,3 ... hasta el número que está probando ... etc. pero para reducir el tiempo de verificación, puede dividir su número por la mitad del valor de su número porque un número no puede ser exactamente divisible por nada por encima de la mitad de su valor. Ejemplo, si desea ver 100, es un número primo que puede recorrer hasta 50.

Código actual :

def find_prime(number):
    if(number ==1):
        return False
    # we are dividiing and rounding and then adding the remainder to increment !
    # to cover not fully divisible value to go up forexample 23 becomes 11
    stop=number//2+number%2
    #loop through up to the half of the values
    for item in range(2,stop):
        if number%item==0:
           return False
        print(number)
    return True


if(find_prime(3)):
    print("it's a prime number !!")
else:
    print("it's not a prime")  

Solo necesita verificar la raíz cuadrada del número, que es bastante más pequeño que la mitad del número. Por ejemplo, para n = 100 solo necesita marcar 10, no 50. ¿Por qué? Exactamente en la raíz cuadrada, los dos factores son iguales. Para cualquier otro factor, uno será menor que sqrt (n) y el otro mayor. Entonces, si no hemos visto uno para el momento en que tenemos el chequeo hasta e incluyendo sqrt (n), no encontraremos uno después.
DanaJ

0

Podemos usar flujos de Java para implementar esto en O (sqrt (n)); Tenga en cuenta que noneMatch es un método shortCircuiting que detiene la operación cuando lo encuentra innecesario para determinar el resultado:

Scanner in = new Scanner(System.in);
int n = in.nextInt();
System.out.println(n == 2 ? "Prime" : IntStream.rangeClosed(2, ((int)(Math.sqrt(n)) + 1)).noneMatch(a -> n % a == 0) ? "Prime" : "Not Prime");

0

Con la ayuda de flujos Java-8 y lambdas, se puede implementar de esta manera en solo unas pocas líneas:

public static boolean isPrime(int candidate){
        int candidateRoot = (int) Math.sqrt( (double) candidate);
        return IntStream.range(2,candidateRoot)
                .boxed().noneMatch(x -> candidate % x == 0);
    }

El rendimiento debe estar cerca de O (sqrt (N)) . Quizás alguien lo encuentre útil.


"range" debe reemplazarse por "rangeClosed" para incluir a candidatoRoot. También se debe manejar el caso candidato <2.
udalmik

¿Cómo es esto diferente de la respuesta anterior de alirezafnatica ?
barba gris

0

Aquí está mi opinión sobre la respuesta:

def isprime(num):
    return num <= 3 or (num + 1) % 6 == 0 or (num - 1) % 6 == 0

La función devolverá True si alguna de las propiedades a continuación es True. Esas propiedades definen matemáticamente qué es un primo.

  1. El número es menor o igual a 3
  2. El número + 1 es divisible por 6
  3. El número - 1 es divisible por 6

>>> isprime(25)vuelve True. Está comprobando una condición necesaria muy simple (divisibilidad por 2 o 3) pero esto no es suficiente .
DanaJ

Bien, estás haciendo coincidir esta propiedad: cada número primo mayor que 3 tiene la forma 6n + 1 o 6n + 5, pero existen números (como 25) que son de la forma 6n + 1 o 6n + 5, pero no son primos
Luis Felipe

0

Cuando tengo que hacer una verificación rápida, escribo este código simple basado en la división básica entre números inferiores a la raíz cuadrada de entrada.

def isprime(n):
    if n%2==0:
        return n==2
    else:
        cota = int(n**0.5)+1
        for ind in range(3,2,cota):
            if n%ind==0:
                print(ind)
                return False
        return True != n==1

isprime(22783)
  • Lo último True != n==1es evitar el caso n=1.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.