Come creare la mappatura più compatta n → isprime (n) fino a un limite N?


152

Naturalmente, poiché bool isprime(number)ci sarebbe una struttura di dati che potrei interrogare.
Mi definisco il miglior algoritmo , per essere l'algoritmo che genera una struttura di dati con il più basso consumo di memoria per l'intervallo (1, N], dove N è una costante.
Solo un esempio di quello che sto cercando: potrei rappresentare ogni numero dispari con un bit, ad es. per l'intervallo di numeri indicato (1, 10], inizia da 3:1110

Il seguente dizionario può essere spremuto di più, giusto? Potrei eliminare multipli di cinque con qualche lavoro, ma i numeri che terminano con 1, 3, 7 o 9 devono essere presenti nella matrice di bit.

Come risolvo il problema?


3
La tua richiesta è un po 'vaga. Dai una firma che testa un singolo numero ma poi chiedi una struttura di dati di (1, N]. Desideri un algoritmo che generi un dizionario <int, bool> o solo una funzione one-shot che controlli se un singolo numero è primo?
Michael Haren,

@Michael Siamo spiacenti, questa è la migliore descrizione che ho potuto trovare. Quello che sto cercando è esattamente come stai dicendo: un dizionario booleano. Vorrei minimizzare lo spazio del dizionario. Grazie :)
AraK,

1
Se è quello che stai cercando, è già stato chiesto: stackoverflow.com/questions/1032427/…
Ben S

14
Dovresti chiedere all'NSA
Charles Bretana il

Risposte:


79

Esistono molti modi per eseguire il test di primalità .

Non esiste davvero una struttura di dati per la query. Se hai molti numeri da testare, probabilmente dovresti eseguire un test probabilistico poiché questi sono più veloci, quindi seguirlo con un test deterministico per assicurarti che il numero sia primo.

Dovresti sapere che la matematica dietro gli algoritmi più veloci non è per i deboli di cuore.


4
Miller-Rabin è un popolare test probabilistico veloce per iniziare.
qwr

214

L'algoritmo più veloce per i test primi generali è AKS . L'articolo di Wikipedia lo descrive a lungo e collega al documento originale.

Se vuoi trovare grandi numeri, guarda i numeri primi che hanno forme speciali come i numeri primi di Mersenne .

L'algoritmo che di solito implemento (facile da capire e codificare) è il seguente (in 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

È una variante O(sqrt(N))dell'algoritmo classico . Usa il fatto che un numero primo (tranne 2 e 3) è di forma 6k - 1o 6k + 1e guarda solo i divisori di questa forma.

A volte, se voglio davvero la velocità e la portata è limitata , implemento un test pseudo-prime basato sul piccolo teorema di Fermat . Se voglio davvero più velocità (cioè evito del tutto l'algoritmo O (sqrt (N)), precomputo i falsi positivi (vedi i numeri di Carmichael ) e faccio una ricerca binaria. Questo è di gran lunga il test più veloce che io abbia mai implementato, l'unico inconveniente è che la gamma è limitata.


7
Due domande: Ci può spiegare meglio ciò che le variabili ie wsono, e che cosa si intende con il modulo 6k-1e 6k+1? Grazie per la tua comprensione e l'esempio di codice (che sto cercando di capire)
Freedom_Ben

6
@Freedom_Ben Ecco qua, quora.com/…
Alan Dong,

6
Non sarebbe meglio calcolare il sqrtdi nuna volta e confrontarlo icon esso, piuttosto che calcolare i * iogni ciclo del ciclo?
Pedro

3
@Dschoni ... ma non puoi adattare l'implementazione più veloce nei campi dei commenti qui per condividerli con noi?
GreenAsJade,

3
Fallisce per il numero 1 :(
Damjan Pavlica,

27

Il metodo migliore, secondo me, è usare ciò che è accaduto prima.

Ci sono elenchi dei primi Nnumeri primi su Internet che si Nestendono fino ad almeno cinquanta milioni . Scarica i file e usali, è probabile che sia molto più veloce di qualsiasi altro metodo che ti verrà in mente.

Se si desidera un algoritmo effettivo per rendere i propri numeri primi, Wikipedia ha tutti i tipi di roba buona in numeri primi qui , compresi i collegamenti ai vari metodi per farlo, e test primario qui , entrambi i metodi probabilistici basati su e veloce-deterministici.

Dovrebbe esserci uno sforzo concertato per trovare i primi miliardi (o anche più) numeri primi e pubblicarli da qualche parte sulla rete in modo che le persone possano smettere di fare lo stesso lavoro ancora e ancora e ancora e ... :-)


2
@hamedbh: interessante. Hai provato a scaricare quei file? Sembra che non esistano.
paxdiablo,

Non ancora, temo: stavo solo guardando in fretta durante la pausa pranzo. Eliminerò quel link nel caso ci sia qualcosa di dannoso al riguardo. Mi dispiace, avrei dovuto prima controllarlo.
Hamed

1
Tali elenchi fanno esistere. Li ho visti anni fa ma non mi è mai importato di scaricarli. La verità è che occupano molto spazio (relativamente parlando) e non dovrebbero essere inclusi nei programmi che uno vende o distribuisce. Inoltre, saranno sempre e per sempre incompleti. In un certo senso ha più senso testare ogni numero che si presenta in pratica durante l'uso di un programma, in quanto un numero inferiore verrà testato in questo modo rispetto alla lunghezza di qualsiasi elenco possiate possedere. Inoltre, penso che pax non capisca che lo scopo degli algoritmi prime, il più delle volte, è testare l'efficienza / velocità piuttosto che trovare realmente i numeri primi.
CogitoErgoCogitoSum

2
@CogitoErgoCogitoSum, sono d'accordo sul fatto che l'elenco di tutti i numeri primi sarà per sempre obsoleto da quando ho visto la prova matematica che sono infiniti. Tuttavia, xè improbabile che l'elenco dei primi numeri primi sia incompleto una volta costruito :-)
paxdiablo

1
È vero, ma esistono metodi di archiviazione migliori rispetto alla lettura da un file in modo lineare. Se vuoi davvero leggere da un set memorizzato di numeri primi pre-generati, prova una struttura di dati più complicata che acceleri il 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;
}

questa è solo l'implementazione c ++ dell'algoritmo AKS sopra


1
È uno degli algoritmi deterministici più efficienti che abbia mai incontrato, sì, ma non è un'implementazione di AKS. Il sistema AKS è molto più recente dell'algoritmo delineato. È probabilmente più efficiente, ma è alquanto difficile da implementare, per esempio, a causa di fattoriali / coefficienti binomiali potenzialmente astronomicamente grandi.
CogitoErgoCogitoSum

In che modo differisce dalla risposta (non) di Derri Leahi (diversa da C invece di Java)? In che modo questa risposta What is the algorithm that produces a data structure with lowest memory consumption for the range (1, N]?
Greybeard,

1
In che modo (n% i == 0 || n% (i + 2) == 0) corrisponde a 6n + 1 e 6n-1?
yesh,

@YeshwanthVenkatesh: How does (n%i == 0 || n%(i+2) == 0) correspond to 6n+1 & 6n-1?parte della risposta è ruoli diversi per n, l'altro è 6n + 1 e 6n-1 equivalente a (6n-1) +0 & (6n-1) + 2 *.
Greybeard,

Si noti inoltre che questo algoritmo non fornisce il risultato corretto per 5e 7.
Athan Clark,

7

Ho confrontato l'efficienza dei suggerimenti più popolari per determinare se un numero è primo. Ho usato python 3.6a ubuntu 17.10; Ho provato con numeri fino a 100.000 (puoi testare con numeri più grandi usando il mio codice qui sotto).

Questo primo diagramma confronta le funzioni (che sono spiegate più avanti nella mia risposta), mostrando che le ultime funzioni non crescono velocemente come la prima quando si aumentano i numeri.

Plot1

E nella seconda trama possiamo vedere che in caso di numeri primi il tempo cresce costantemente, ma i numeri non primi non crescono così velocemente nel tempo (perché la maggior parte di essi può essere eliminata all'inizio).

Plot2

Ecco le funzioni che ho usato:

  1. questa risposta e questa risposta hanno suggerito un costrutto 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. Questa risposta utilizzava una sorta di 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. Questa risposta includeva una versione con un forciclo:

    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. E ho mescolato alcune idee dalle altre risposte in una nuova:

    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
    

Ecco il mio script per confrontare le varianti:

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

Eseguendo la funzione compare_functions(n=10**5)(numeri fino a 100.000) Ottengo questo risultato:

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 |
 ---------------------------------------------------------------------

Quindi, eseguendo la funzione compare_functions(n=10**6)(numeri fino a 1.000.000) ottengo questo output:

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 |
 ---------------------------------------------------------------------

Ho usato il seguente script per tracciare i risultati:

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

Si può usare Sympy .

import sympy

sympy.ntheory.primetest.isprime(33393939393929292929292911111111)

True

Dai documenti di Sympy. Il primo passo è alla ricerca di fattori insignificanti, che se trovati consentono un rapido ritorno. Quindi, se il setaccio è abbastanza grande, utilizzare la ricerca bisettrice sul setaccio. Per piccoli numeri, viene eseguita una serie di test deterministici di Miller-Rabin con basi che non hanno controesempi nel loro intervallo. Infine, se il numero è maggiore di 2 ^ 64, viene eseguito un forte test BPSW. Sebbene si tratti di un probabile primo test e riteniamo che esistano controesempi, non ci sono controesempi noti


Un algoritmo è una sequenza di passaggi ben definiti che definisce una soluzione astratta a un problema. - qual è la sequenza immaginabile di passaggi nel codice presentato? Che cos'è memory consumption?
Greybeard,

2
@greybeard. Dai documenti di Sympy. Il primo passo è alla ricerca di fattori insignificanti, che se trovati consentono un rapido ritorno. Quindi, se il setaccio è abbastanza grande, utilizzare la ricerca bisettrice sul setaccio. Per piccoli numeri, viene eseguita una serie di test deterministici di Miller-Rabin con basi che non hanno controesempi nel loro intervallo. Infine, se il numero è maggiore di 2 ^ 64, viene eseguito un forte test BPSW. Sebbene si tratti di un probabile primo test e riteniamo che esistano controesempi, non esistono controesempi noti.
LetzerWille,

6

In 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))

Spiegazione: Un numero primo è un numero divisibile solo per sé e 1. Es: 2,3,5,7 ...

1) se a <2: se "a" è inferiore a 2 non è un numero primo.

2) elif a! = 2 e a% 2 == 0: se "a" è divisibile per 2, allora sicuramente non è un numero primo. Ma se a = 2 non vogliamo valutarlo poiché si tratta di un numero primo. Da qui la condizione a! = 2

3) restituisce tutto (a% i per i nell'intervallo (3, int (a 0,5) +1)): ** Primo sguardo a cosa fa il comando all () in python. A partire da 3 dividiamo "a" fino alla sua radice quadrata (a ** 0,5). Se "a" è divisibile, l'output sarà False. Perché radice quadrata? Diciamo a = 16. La radice quadrata di 16 = 4. Non abbiamo bisogno di valutare fino a 15. Dobbiamo solo controllare fino a 4 per dire che non è un numero primo.

Extra: un ciclo per trovare tutti i numeri primi all'interno di un intervallo.

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

1
In cosa differisce dalla risposta di Oleksandr Shmyheliuk ? (Entrambi mancano un "passaggio 2" in range()...)
Barbarossa il

1
Se un numero è pari, non è un numero primo (esclusi 2). Quindi non c'è bisogno di controllare i numeri pari. Questo sarà molto più veloce se vuoi ottenere il numero primo all'interno di un intervallo. Direttamente verso l'alto escluderà i numeri pari.
Deep growal,


3

Per numeri grandi non puoi semplicemente verificare ingenuamente se il numero candidato N è divisibile per nessuno dei numeri inferiori a sqrt (N). Sono disponibili molti più test scalabili, come il test di primalità di Miller-Rabin . Di seguito hai l'implementazione in 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

Puoi usarlo per trovare enormi numeri primi:

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

# 10000000000000000000000000000000000000000000000000000000000000000000000000133 is a prime!

Se stai testando numeri interi casuali, probabilmente vuoi prima verificare se il numero candidato è divisibile per uno dei numeri primi più piccoli di, diciamo 1000, prima di chiamare Miller-Rabin. Questo ti aiuterà a filtrare ovvi non primi come 10444344345.


Questo è il test di Miller. Il test di Miller-Rabin è la versione probabilistica in cui vengono testate basi selezionate casualmente fino a quando non viene raggiunta una sicurezza sufficiente. Inoltre, il test di Miller non dipende direttamente dall'ipotesi di Riemann, ma dall'ipotesi di Riemann generalizzata (GRH) per i personaggi di Diriclet quadratici (so che è un boccone e non lo capisco neanche io). Il che significa che una potenziale prova dell'ipotesi di Riemann potrebbe non applicarsi nemmeno al GRH, e quindi non provare il test di Miller corretto. Un caso ancora peggiore sarebbe ovviamente se il GRH fosse confutato.
Arne Vogel,

2

Troppo tardi alla festa, ma spero che questo aiuti. Questo è rilevante se stai cercando grandi numeri primi:

Per testare numeri dispari di grandi dimensioni è necessario utilizzare il test Fermat e / o il test Miller-Rabin.

Questi test usano esponenziazione modulare che è piuttosto costosa, per l' nespiazione dei bit è necessaria almeno una nmoltiplicazione di int e un ndiv di int. Ciò significa che la complessità dell'espiazione modulare è O (n³).

Quindi, prima di usare le pistole grandi, devi fare alcune divisioni di prova. Ma non farlo ingenuamente, c'è un modo per farli in fretta. Innanzitutto moltiplica quanti più numeri primi quanti si adattano alle parole che usi per i grandi numeri interi. Se usi parole a 32 bit, moltiplica 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23 * 29 = 3234846615 e calcola il massimo comune divisore per il numero che collaudi usando l'algoritmo euclideo. Dopo il primo passo, il numero viene ridotto al di sotto della dimensione della parola e continua l'algoritmo senza eseguire divisioni complete di numeri interi grandi. Se il GCD! = 1, significa che uno dei numeri primi che hai moltiplicato insieme divide il numero, quindi hai una prova che non è primo. Quindi continuare con 31 * 37 * 41 * 43 * 47 = 95041567 e così via.

Dopo aver testato diverse centinaia (o migliaia) numeri primi in questo modo, puoi fare 40 round di test di Miller-Rabin per confermare che il numero è primo, dopo 40 round puoi essere certo che il numero è primo, ci sono solo 2 ^ -80 possibilità che sia no (è più probabile un malfunzionamento dell'hardware ...).


1

Ho una funzione primaria che funziona fino a (2 ^ 61) -1 Qui:

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

Spiegazione:

La all()funzione può essere ridefinita in questo modo:

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

La all()funzione passa attraverso una serie di bool / numeri e ritorna Falsese vede 0 o False.

La sqrt()funzione sta semplicemente eseguendo la radice quadrata di un numero.

Per esempio:

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

La num % xparte restituisce il resto di num / x.

Infine, range(2, int(sqrt(num)))significa che creerà un elenco che inizia da 2 e termina aint(sqrt(num)+1)

Per ulteriori informazioni sulla gamma, dai un'occhiata a questo sito Web !

La num > 1parte sta solo verificando se la variabile numè maggiore di 1, perché 1 e 0 non sono considerati numeri primi.

Spero che questo abbia aiutato :)


Per favore, argomenta come si tratta di un the bestalgoritmo, o addirittura buono .
greybeard,

@greybeard, La maggior parte delle funzioni principali qui non aumenta fino a (2 ^ 31) -1 o impiega troppo tempo per i numeri alti, ma la mia funziona fino a (2 ^ 61) -1, quindi puoi verificare se un numero è primo con un numero maggiore intervallo di numeri.
WhyAreYouReadingQuesto

1

In Python:

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

Una conversione più diretta dal formalismo matematico in Python userebbe tutto (n% p! = 0 ...) , ma ciò richiede una valutazione rigorosa di tutti i valori di p. La mancata versione può terminare in anticipo se viene trovato un valore True.


Wrt "all (n% p! = 0 ...), ma ciò richiede una rigorosa valutazione di tutti i valori di p" - non è corretto. anye allusciranno entrambi presto . Così, alla prima pin cui n % pè 0, allsarebbe uscire.
aneroide

1

miglior algoritmo per il numero di 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 numero primo è qualsiasi numero che è divisibile solo per 1 e per se stesso. Tutti gli altri numeri sono chiamati compositi .

Il modo più semplice, di trovare un numero primo, è verificare se il numero di input è un numero composto:

    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;
    }

Il programma deve dividere il valore di numberper tutti i numeri interi da 1 e fino al suo valore. Se questo numero può essere diviso uniformemente non solo per uno e per se stesso, è un numero composto.

Il valore iniziale della variabile ideve essere 2 perché sia ​​i numeri primi che quelli compositi possono essere divisi uniformemente per 1.

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

Quindi iè inferiore rispetto numberallo stesso motivo. I numeri primi e composti possono essere divisi uniformemente da soli. Pertanto non c'è motivo di verificarlo.

Quindi controlliamo se la variabile può essere divisa in modo uniforme utilizzando l'operatore restante.

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

Se il resto è zero significa che numberpuò essere diviso uniformemente, quindi essendo un numero composto e restituendo false.

Se il numero inserito non ha soddisfatto la condizione, significa che è un numero primo e la funzione restituisce vero.


1
(Mentre penso a simplestuna valida interpretazione del migliore :) La domanda è: qual è l'algoritmo migliore per verificare se un numero è primo? : Il controllo della divisibilità è number / 2 < i < numbervantaggioso? Che dire number < i*i? Cosa dicono le comprensibili delle altre 3 3 risposte?
Greybeard,

1

Lascia che ti suggerisca la soluzione perfetta per numeri interi a 64 bit. Mi dispiace usare C #. Non l'hai già specificato come Python nel tuo primo post. Spero che tu possa trovare una semplice funzione modPow e analizzarla facilmente.

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;
}

per qualsiasi numero, le iterazioni minime per verificare se il numero è primo o no possono essere comprese tra 2 e la radice quadrata del numero. Per ridurre le iterazioni, ancora di più, possiamo verificare se il numero è divisibile per 2 o 3 poiché i numeri massimi possono essere eliminati controllando se il numero è divisibile per 2 o 3. Inoltre, qualsiasi numero primo maggiore di 3 può essere espresso come 6k +1 o 6k-1. Quindi l'iterazione può andare da 6k + 1 alla radice quadrata del numero.


1
Sarebbe meglio se aggiungessi qualche spiegazione alla tua risposta usando edit . A molti lettori potrebbe non essere chiaro il motivo per cui la tua risposta è buona e potrebbero imparare da te se spiegassi di più.
Brian Tompsett - 莱恩 莱恩

0

Memoria più piccola? Questo non è il più piccolo, ma è un passo nella giusta direzione.

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];
    }
}

Certo, devi specificare la definizione di CheckPrimality.


0

Penso che uno dei più veloci sia il mio metodo che ho realizzato.

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 errore potrebbe essere ... 6 - io?
Hmmm,

0

Idea simile all'algoritmo AKS che è stato menzionato

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
Nessuna relazione con l' algoritmo AKS .
Greybeard,

Nel ciclo for non è necessario selezionare "i <= limite", è sufficiente selezionare "i <limite". Quindi in ogni iterazione fai un confronto in meno.
Andrushenko Alexander,

0

Per scoprire se il numero o i numeri in un intervallo sono / sono primi.

#!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.

Esegui questo codice funzionerà sia per un elenco che per un numero particolare
Harsh Singh,

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
Quando scrivi una risposta, anche se è corretta, ti preghiamo anche di scrivere un po 'spiegando cosa stai facendo e perché. In questo modo le persone che leggono la tua risposta possono capire più facilmente ciò che hai risolto. Grazie!
Kim

1
Sicuro Kim, grazie per averlo sottolineato. Questo è il mio primo programma in StackOverflow da ora in poi aggiungerò commenti e spiegazioni appropriate.
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

Potresti provare qualcosa del genere.

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()

Questa è una soluzione terribile per testare il primeness. Una volta trovato un divisore, conosci la risposta, ma questo codice trova tutti i divisori e quindi decide! E ignora la richiesta del PO di un predicato booleano come sempre ritorna None.
cdlane,

@cdlane so che questa non è una funzione booleana di ritorno, sono ancora un principiante in Python e so che non è perfetto, grazie per aver commentato comunque
Patrick Jane

0

La maggior parte delle risposte precedenti sono corrette, ma qui c'è un altro modo per verificare se un numero è il numero primo. Come aggiornamento, i numeri primi sono numeri interi maggiori di 1 i cui unici fattori sono 1 e se stesso ( fonte )

Soluzione:

In genere puoi creare un ciclo e iniziare a testare il tuo numero per vedere se è divisibile per 1,2,3 ... fino al numero che stai testando ... ecc. Ma per ridurre i tempi di verifica, puoi dividere il numero per metà del valore del tuo numero perché un numero non può essere esattamente divisibile per nulla superiore alla metà del suo valore. Esempio se vuoi vedere 100 è un numero primo che puoi scorrere fino a 50.

Codice reale :

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")  

Devi solo controllare la radice quadrata del numero, che è un po 'più piccola della metà del numero. Ad esempio per n = 100 devi solo selezionare 10, non 50. Perché? Esattamente alla radice quadrata, i due fattori sono uguali. Per ogni altro fattore uno sarà inferiore a sqrt (n) e l'altro più grande. Quindi, se non ne abbiamo visto uno entro il momento in cui abbiamo eseguito il controllo fino a sqrt (n) incluso, non ne troveremo uno dopo.
DanaJ,

0

Possiamo usare java stream per implementarlo in O (sqrt (n)); Considera che noneMatch è un metodo shortCircuiting che interrompe l'operazione quando non è necessario per determinare il risultato:

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 l'aiuto di stream e lambda Java-8, può essere implementato in questo modo in poche righe:

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

Le prestazioni dovrebbero essere vicine a O (sqrt (N)) . Forse qualcuno lo trova utile.


"range" deve essere sostituito con "rangeClosed" per includere candidateRoot. Anche il caso candidato <2 deve essere gestito.
udalmik,


0

Ecco la mia opinione sulla risposta:

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

La funzione restituirà True se una delle proprietà seguenti è True. Tali proprietà definiscono matematicamente cos'è un numero primo.

  1. Il numero è inferiore o uguale a 3
  2. Il numero + 1 è divisibile per 6
  3. Il numero - 1 è divisibile per 6

>>> isprime(25)ritorna True. Stai verificando una condizione necessaria molto semplice (divisibilità per 2 o 3) ma non è sufficiente .
DanaJ,

Bene, stai abbinando con questa proprietà: ogni numero primo maggiore di 3 è della forma 6n + 1 o 6n + 5, ma esistono numeri (come 25) che sono della forma 6n + 1 o 6n + 5, ma essi non sono primi
Luis Felipe il

0

Quando devo fare una verifica veloce, scrivo questo semplice codice basato sulla divisione di base tra numeri inferiori alla radice quadrata dell'input.

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)
  • L'ultimo True != n==1è quello di evitare il caso n=1.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.