web-dev-qa-db-fra.com

Simple Prime Generator en Python

Est-ce que quelqu'un pourrait me dire ce que je fais de mal avec ce code? De toute façon, c'est juste l'impression de "compter". Je veux juste un générateur de prime très simple (rien d'extraordinaire). 

import math

def main():
    count = 3
    one = 1
    while one == 1:
        for x in range(2, int(math.sqrt(count) + 1)):
            if count % x == 0: 
                continue
            if count % x != 0:
                print count

        count += 1
30
marc lincoln

Il y a quelques problèmes:

  • Pourquoi imprimez-vous le nombre quand il ne s'est pas divisé en x? Cela ne signifie pas que c'est premier, cela signifie seulement que ce x particulier ne le divise pas
  • continue passe à la prochaine itération de la boucle - mais vous voulez vraiment l'arrêter en utilisant break

Voici votre code avec quelques corrections, il n’imprime que les nombres premiers:

import math

def main():
    count = 3
    
    while True:
        isprime = True
        
        for x in range(2, int(math.sqrt(count) + 1)):
            if count % x == 0: 
                isprime = False
                break
        
        if isprime:
            print count
        
        count += 1

Pour une génération de choix beaucoup plus efficace, consultez le tamis d'Erastothenes, comme d'autres l'ont suggéré. Voici une belle implémentation optimisée avec de nombreux commentaires:

# Sieve of Eratosthenes
# Code by David Eppstein, UC Irvine, 28 Feb 2002
# http://code.activestate.com/recipes/117119/

def gen_primes():
    """ Generate an infinite sequence of prime numbers.
    """
    # Maps composites to primes witnessing their compositeness.
    # This is memory efficient, as the sieve is not "run forward"
    # indefinitely, but only as long as required by the current
    # number being tested.
    #
    D = {}
    
    # The running integer that's checked for primeness
    q = 2
    
    while True:
        if q not in D:
            # q is a new prime.
            # Yield it and mark its first multiple that isn't
            # already marked in previous iterations
            # 
            yield q
            D[q * q] = [q]
        else:
            # q is composite. D[q] is the list of primes that
            # divide it. Since we've reached q, we no longer
            # need it in the map, but we'll mark the next 
            # multiples of its witnesses to prepare for larger
            # numbers
            # 
            for p in D[q]:
                D.setdefault(p + q, []).append(p)
            del D[q]
        
        q += 1

Notez que cela retourne un générateur.

140
Eli Bendersky
def is_prime(num):
    """Returns True if the number is prime
    else False."""
    if num == 0 or num == 1:
        return False
    for x in range(2, num):
        if num % x == 0:
            return False
    else:
        return True

>> filter(is_prime, range(1, 20))
  [2, 3, 5, 7, 11, 13, 17, 19]

Nous aurons tous les nombres premiers jusqu’à 20 dans une liste ..__ J'aurais pu utiliser Sieve of Eratosthenes mais vous avez dit.__ vous voulez quelque chose de très simple ;)

12
aatifh
print [x for x in range(2,100) if not [t for t in range(2,x) if not x%t]]
7
SergioAraujo

re est puissant:

import re


def isprime(n):
    return re.compile(r'^1?$|^(11+)\1+$').match('1' * n) is None

print [x for x in range(100) if isprime(x)]

###########Output#############
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
6
FelixHo
def primes(n): # simple Sieve of Eratosthenes 
   odds = range(3, n+1, 2)
   sieve = set(sum([range(q*q, n+1, q+q) for q in odds],[]))
   return [2] + [p for p in odds if p not in sieve]

>>> primes(50)
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]

Pour tester si un nombre est premier:

>>> 541 in primes(541)
True
>>> 543 in primes(543)
False
4
dansalmo

Voici une solution simple (Python 2.6.2) ... conforme à la demande initiale du PO (maintenant âgée de six mois); et devrait être une solution parfaitement acceptable dans tout cours de "programmation 101" ... D'où ce post.

import math

def isPrime(n):
    for i in range(2, int(math.sqrt(n)+1)):
        if n % i == 0: 
            return False;
    return n>1;

print 2
for n in range(3, 50):
    if isPrime(n):
        print n

Cette méthode simple de "force brute" est "assez rapide" pour des nombres allant jusqu'à environ 16 000 sur les PC modernes (cela a pris environ 8 secondes sur ma boîte à 2 GHz).

Évidemment, cela pourrait être fait beaucoup plus efficacement, en ne recalculant pas la primauté de chaque nombre pair, ni de tous les multiples de 3, 5, 7, etc. pour chaque nombre ... Voir le tamis d'Eratosthène ( voir l'implémentation de eliben ci-dessus), ou même le tamis d'Atkin si vous vous sentez particulièrement courageux et/ou fou.

Caveat Emptor: Je suis un noob en python. S'il vous plaît ne prenez pas ce que je dis comme évangile.

3
corlettk

À mon avis, il est toujours préférable d'adopter l'approche fonctionnelle,

Donc, je crée d'abord une fonction pour savoir si le nombre est premier ou non, puis l'utiliser en boucle ou à un autre endroit si nécessaire.

def isprime(n):
      for x in range(2,n):
        if n%x == 0:
            return False
    return True

Ensuite, lancez une simple compréhension de liste ou une expression génératrice pour obtenir votre liste de nombres premiers,

[x for x in range(1,100) if isprime(x)]
2
mmrs151

Un autre exemple simple, avec une optimisation simple consistant à ne considérer que les nombres impairs. Tout est fait avec des flux paresseux (générateurs de python).

Usage: primes = list (create_prime_iterator (1, 30))

import math
import itertools

def create_prime_iterator(rfrom, rto):
    """Create iterator of prime numbers in range [rfrom, rto]"""
    prefix = [2] if rfrom < 3 and rto > 1 else [] # include 2 if it is in range separately as it is a "weird" case of even prime
    odd_rfrom = 3 if rfrom < 3 else make_odd(rfrom) # make rfrom an odd number so that  we can skip all even nubers when searching for primes, also skip 1 as a non prime odd number.
    odd_numbers = (num for num in xrange(odd_rfrom, rto + 1, 2))
    prime_generator = (num for num in odd_numbers if not has_odd_divisor(num))
    return itertools.chain(prefix, prime_generator)

def has_odd_divisor(num):
    """Test whether number is evenly divisable by odd divisor."""
    maxDivisor = int(math.sqrt(num))
    for divisor in xrange(3, maxDivisor + 1, 2):
        if num % divisor == 0:
            return True
    return False

def make_odd(number):
    """Make number odd by adding one to it if it was even, otherwise return it unchanged"""
    return number | 1
1
Sharas

Que diriez-vous de cela si vous voulez calculer directement le nombre premier:

def oprime(n):
counter = 0
b = 1
if n == 1:
    print 2
while counter < n-1:
    b = b + 2
    for a in range(2,b):
        if b % a == 0:
            break
    else:
        counter = counter + 1
        if counter == n-1:
            print b
1
Jitender Shekhawat

Cela semble être un devoir, alors je vais donner un indice plutôt qu'une explication détaillée. Corrigez-moi si j'ai mal compris.

Vous vous en sortez aussi bien que de sauver quand vous voyez un diviseur même. 

Mais vous imprimez 'compte' dès que vous voyez même un nombre qui ne se divise pas en. 2, par exemple, ne se divise pas également en 9. Mais cela ne fait pas de 9 un nombre premier. Vous voudrez peut-être continuer jusqu'à ce que vous soyez sûr que no nombre dans la plage correspond.

(comme d'autres l'ont répondu, un tamis est un moyen beaucoup plus efficace de s'y rendre ... juste pour vous aider à comprendre pourquoi ce code spécifique ne fait pas ce que vous voulez)

1
Paul Roub

SymPy est une bibliothèque Python pour les mathématiques symboliques. Il fournit plusieurs fonctions pour générer des nombres premiers.

isprime(n)              # Test if n is a prime number (True) or not (False).

primerange(a, b)        # Generate a list of all prime numbers in the range [a, b).
randprime(a, b)         # Return a random prime number in the range [a, b).
primepi(n)              # Return the number of prime numbers less than or equal to n.

prime(nth)              # Return the nth prime, with the primes indexed as prime(1) = 2. The nth prime is approximately n*log(n) and can never be larger than 2**n.
prevprime(n, ith=1)     # Return the largest prime smaller than n
nextprime(n)            # Return the ith prime greater than n

sieve.primerange(a, b)  # Generate all prime numbers in the range [a, b), implemented as a dynamically growing sieve of Eratosthenes. 

Voici quelques exemples.

>>> import sympy
>>> 
>>> sympy.isprime(5)
True
>>> list(sympy.primerange(0, 100))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
>>> sympy.randprime(0, 100)
83
>>> sympy.randprime(0, 100)
41
>>> sympy.prime(3)
5
>>> sympy.prevprime(50)
47
>>> sympy.nextprime(50)
53
>>> list(sympy.sieve.primerange(0, 100))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
0
SparkAndShine

Si vous voulez trouver tous les nombres premiers dans une plage, vous pouvez le faire: 

def is_prime(num):
"""Returns True if the number is prime
else False."""
if num == 0 or num == 1:
    return False
for x in range(2, num):
    if num % x == 0:
        return False
else:
    return True
num = 0
itr = 0
tot = ''
while itr <= 100:
    itr = itr + 1
    num = num + 1
    if is_prime(num) == True:
        print(num)
        tot = tot + ' ' + str(num)
print(tot)

Ajoutez simplement while its <= et votre numéro pour la plage.
SORTIE:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101

0
user9311010

Voici ce que j'ai

def is_prime(num):
    if num < 2:         return False
    Elif num < 4:       return True
    Elif not num % 2:   return False
    Elif num < 9:       return True
    Elif not num % 3:   return False
    else:
        for n in range(5, int(math.sqrt(num) + 1), 6):
            if not num % n:
                return False
            Elif not num % (n + 2):
                return False

    return True

C'est assez rapide pour les grands nombres, car il vérifie uniquement les nombres premiers des diviseurs d'un nombre.

Maintenant, si vous voulez générer une liste de nombres premiers, vous pouvez faire:

# primes up to 'max'
def primes_max(max):
    yield 2
    for n in range(3, max, 2):
        if is_prime(n):
            yield n

# the first 'count' primes
def primes_count(count):
    counter = 0
    num = 3

    yield 2

    while counter < count:
        if is_prime(num):
            yield num
            counter += 1
        num += 2

utiliser des générateurs ici pourrait être souhaité pour l'efficacité.

Et juste pour référence, au lieu de dire:

one = 1
while one == 1:
    # do stuff

vous pouvez simplement dire:

while 1:
    #do stuff
0
fengshaun

Semblable à user107745, mais en utilisant "tous" au lieu de la double négation (un peu plus lisible, mais je pense même performance):

import math
[x for x in xrange(2,10000) if all(x%t for t in xrange(2,int(math.sqrt(x))+1))]

Fondamentalement, il itère sur x dans la plage de (2, 100) et ne sélectionne que ceux qui n'ont pas mod == 0 pour tous les t dans la plage (2, x)

Une autre façon consiste probablement à renseigner les nombres premiers au fur et à mesure:

primes = set()
def isPrime(x):
  if x in primes:
    return x
  for i in primes:
    if not x % i:
      return None
  else:
    primes.add(x)
    return x

filter(isPrime, range(2,10000))
0
vtlinh

Vous pouvez créer une liste de nombres premiers en utilisant des interprétations de liste de manière assez élégante. Tiré de ici:

>>> noprimes = [j for i in range(2, 8) for j in range(i*2, 50, i)]
>>> primes = [x for x in range(2, 50) if x not in noprimes]
>>> print primes
>>> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47]
0
randlet
  • La déclaration continue semble fausse.

  • Vous voulez commencer à 2 car 2 est le premier nombre premier.

  • Vous pouvez écrire "while True:" pour obtenir une boucle infinie.

0
starblue
def genPrimes():
    primes = []   # primes generated so far
    last = 1      # last number tried
    while True:
        last += 1
        for p in primes:
            if last % p == 0:
                break
        else:
            primes.append(last)
            yield last
0
Kuldeep K. Rishi
def check_prime(x):
    if (x < 2): 
       return 0
    Elif (x == 2): 
       return 1
    t = range(x)
    for i in t[2:]:
       if (x % i == 0):
            return 0
    return 1
0
kn3l

Vous devez vous assurer que tous les diviseurs possibles ne divisent pas le nombre que vous vérifiez. Dans ce cas, vous imprimerez le numéro que vous vérifiez à tout moment, mais l’un des diviseurs possibles ne le divise pas de manière égale.

De plus, vous ne voulez pas utiliser une instruction continue, car continuer lui permettra simplement de vérifier le prochain diviseur possible lorsque vous avez déjà découvert que le nombre n'est pas un nombre premier.

0
David Locke

Voici une version numpy de Sieve of Eratosthenes présentant à la fois une complexité satisfaisante (inférieure au tri d’un tableau de longueur n) et une vectorisation.

import numpy as np 
def generate_primes(n):
    is_prime = np.ones(n+1,dtype=bool)
    is_prime[0:2] = False
    for i in range(int(n**0.5)+1):
        if is_prime[i]:
            is_prime[i*2::i]=False
    return np.where(is_prime)[0]

Horaires: 

import time    
for i in range(2,10):
    timer =time.time()
    generate_primes(10**i)
    print('n = 10^',i,' time =', round(time.time()-timer,6))

>> n = 10^ 2  time = 5.6e-05
>> n = 10^ 3  time = 6.4e-05
>> n = 10^ 4  time = 0.000114
>> n = 10^ 5  time = 0.000593
>> n = 10^ 6  time = 0.00467
>> n = 10^ 7  time = 0.177758
>> n = 10^ 8  time = 1.701312
>> n = 10^ 9  time = 19.322478
0