2015-01-08 23 views
5

Attualmente ho impostato ↓ come funzione randprime(p,q). C'è un modo per condensare questo, tramite qualcosa come un gene o listcomp? Ecco la mia funzione:Numero casuale primo in python

n = randint(p, q) 
while not isPrime(n): 
    n = randint(p, q) 
+6

Sembra che sarebbe meglio generare un elenco di numeri primi tra 'p' e' q' e quindi scegliere uno casuale da quella lista. –

+0

È possibile aumentare le probabilità che un numero sia primo impostando il bit più basso su 1, rendendolo così strano - c'è solo un primo numero pari, ovvero 2. In realtà, tutti i numeri primi diversi da 2 e 3 sono uno sotto o uno sopra un multiplo di sei. –

+1

Odio quando qualcuno proroga una domanda senza dire perché, perché l'OP non può risolverlo se non sa cosa è sbagliato. –

risposta

4

È meglio solo generare l'elenco di numeri primi e quindi scegliere da quella linea. Così com'è, con il tuo codice c'è la sottile possibilità che colpirà un ciclo infinito, o se non ci sono numeri primi nell'intervallo o se randint seleziona sempre un non-prime, quindi il ciclo while non finirà mai.

Quindi questo è probabilmente più breve e meno fastidioso:

import random 
primes = [i for i in range(p,q) if isPrime(i)] 
n = random.choice(primes) 

L'altro vantaggio di questo è che non c'è alcuna possibilità di stallo se non ci sono numeri primi nell'intervallo. Come detto questo può essere lento a seconda del campo, quindi sarebbe più veloce se memorizzato nella cache i numeri primi prima del tempo:

# initialising primes 
minPrime = 0 
maxPrime = 1000 
cached_primes = [i for i in range(minPrime,maxPrime) if isPrime(i)] 

#elsewhere in the code 
import random 
n = random.choice([i for i in cached_primes if p<i<q]) 

Anche in questo caso, ulteriori ottimizzazioni sono possibili, ma sono molto dipende dal codice vero e proprio .. e tu sai cosa dicono di ottimizzazioni premature.

+2

Questa può essere una pessima idea se p e q sono dell'ordine 10 ** 10, che è una cosa ragionevole da provare se stai pensando alla crittografia. – Joel

+0

Suppongo che se ci sono dei primi tra 'p' e' q', si verificheranno sicuramente dei blocchi. –

+0

Bene, presumibilmente inseriscono nella cache il controllo 'isPrime', o hanno un elenco precompilato su cui lavorare. –

-1
next(i for i in itertools.imap(lambda x: random.randint(p,q)|1,itertools.count()) if isPrime(i)) 

Questo inizia con itertools.count() - questo dà un insieme infinito.

Ogni numero è mappato a un nuovo numero casuale nell'intervallo, da itertools.imap(). imap è come una mappa, ma restituisce un iteratore, piuttosto che una lista - non vogliamo generare una lista di numeri casuali inifiniti!

Quindi, il primo numero corrispondente viene trovato e restituito.

Funziona in modo efficiente, anche se p e q sono molto distanti - ad es. 1 e 10 ** 30, che non generano una lista completa!

A proposito, questo non è più efficiente del tuo codice sopra, ed è molto più difficile da capire a colpo d'occhio - ti preghiamo di avere qualche considerazione per il prossimo programmatore di dover leggere il tuo codice, e fallo come hai fatto sopra. Quel programmatore potrebbe essere tu tra sei mesi, quando hai dimenticato cosa doveva fare questo codice!

P.S - in pratica, si potrebbe voler sostituire count() con xrange (NON range!) Ad es. xrange((p-q)**1.5+20) non fare più di quel numero di tentativi (bilanciati tra test limitati per intervalli piccoli e grandi gamme, e non ha più dell'1/2% di possibilità di fallire se potesse riuscire), altrimenti, come è stato suggerito in un altro post, potrebbe loop per sempre.

PPS - miglioramento: sostituito random.randint(p,q) con random.randint(p,q)|1 - questo rende il codice di due volte più efficiente, ma elimina la possibilità che il risultato sarà 2.

+0

Ho considerato q-p, e quindi semplificato in p, e quindi 'p ** 2'. La mia ultima risposta (appena decisa) è (q-p) ** 2. q-p probabilmente non è abbastanza; Se hai due numeri e uno di questi è un numero primo (ad esempio q = 18 ep = 19), allora hai una probabilità del 25% di fallimento. Man mano che l'intervallo aumenta, le possibilità di coprire tutti i numeri dell'intervallo diminuiscono (campionando i numeri casuali dell'intervallo nell'intervallo). –

+0

Avendo fatto un po 'di caccia, uno scenario molto brutto sta scegliendo p = 1425172824437699411, e q = p + 1475; in quell'intervallo di numeri, c'è solo un primo (e 1475 non-primi). Ognuno ha una probabilità 1475/1476 di essere un non-prime, quindi anche 1476 tentativi ha una probabilità del 37% di fallire. –

+0

Un altro calcolo mostra che i tentativi '(q-p) ** 2' potrebbero non essere sufficienti - per q = p + 1 (dove p o q è primo), c'è una probabilità del 6% di fallimento per quei molti (= 4) test. Rivedrò la mia risposta a '(q-p) ** 2 + 20', che sarà solo leggermente più lento e funzionerà meglio per i piccoli numeri. –

0

Quindi sarebbe bello se si potesse usare un iteratore per dare il numeri interi da p a q in ordine casuale (senza sostituzione). Non sono stato in grado di trovare un modo per farlo. Quanto segue fornirà numeri interi casuali in quell'intervallo e salterà qualsiasi cosa che sia già stata testata.

import random 
fail = False 
tested = set([]) 
n = random.randint(p,q) 
while not isPrime(n): 
    tested.add(n) 
    if len(tested) == p-q+1: 
     fail = True 
     break 
    while n in s: 
     n = random.randint(p,q) 

if fail: 
    print 'I failed' 
else: 
    print n, ' is prime' 

Il grande vantaggio di questo è che se dire la gamma si sta testando è solo (14,15), il codice sarebbe correre per sempre.Questo codice è garantito per produrre una risposta se esiste un tale primo e dire che non ce n'è uno se tale primo non esiste. Ovviamente puoi renderlo più compatto, ma sto cercando di mostrare la logica.

+0

Sì, ma il mio finirà se viene assegnato un intervallo senza un primo, e verrà eseguito in un tempo notevolmente inferiore se si fornisce un intervallo con solo pochi numeri primi. Il codice – Joel

+3

dell'OP è di 3 righe ma si bloccherà se non ci sono primi tra p e q, quindi non è sicuro. –

+0

Ero io e ti ho votato perché la tua risposta, mentre introducevo qualcosa di utile, è l'ESATTO OPPOSTO di ciò che veniva chiesto: "C'è un modo per condensare questo?". Ho dato credito che quella parte non era mia. Non era la base della mia risposta, solo una nota a piè di pagina. Siete invitati a incorporare il mio codice nella risposta come nota a piè di pagina (o idee da esso). –