web-dev-qa-db-fra.com

Python Trouver les facteurs premiers

Question en deux parties ...

1) Essayer de déterminer le plus grand facteur premier de 600851475143, a trouvé ce programme en ligne qui semble fonctionner, le problème est que j'ai du mal à comprendre comment cela fonctionne (je comprends les bases du fonctionnement du programme) ... Si vous pouviez également éclaircir n'importe quelle méthode que vous connaissez, il est peut-être primordial de déterminer la valeur de prime (peut-être même sans tester tous les nombres) et de connaître le fonctionnement de votre méthode.

Le code que j'ai trouvé en ligne pour le facteur premier

n = 600851475143
i = 2
while i * i < n:
     while n % i == 0:
         n = n / i
     i = i + 1

print (n)

#takes about ~0.01secs

2) Pourquoi le code est-il tellement plus rapide que ce code (le code est juste pour tester la vitesse et n'a pas d'autre but que celui-là)

i = 1
while i < 100:
    i += 1
#takes about ~3secs
32
francium

Cette question était le premier lien qui a surgi lorsque j'ai googlé "python prime factorization". Comme l'a souligné @ quangpn88, cet algorithme est faux (!) pour les carrés parfaits tels que n = 4, 9, 16, ... Cependant, le correctif de @ quangpn88 ne fonctionne pas non plus, car il produira des résultats incorrects si le plus grand facteur premier se produit 3 ou plusieurs fois, par exemple, n = 2*2*2 = 8 ou n = 2*3*3*3 = 54.

Je crois qu'un algorithme correct, force brute en Python est:

def largest_prime_factor(n):
    i = 2
    while i * i <= n:
        if n % i:
            i += 1
        else:
            n //= i
    return n

N'utilisez pas ceci dans le code de performance, mais c'est correct pour les tests rapides avec des nombres modérément grands:

In [1]: %timeit largest_prime_factor(600851475143)
1000 loops, best of 3: 388 µs per loop

Si la factorisation en nombre premier complète est recherchée, il s'agit de l'algorithme de force brute:

def prime_factors(n):
    i = 2
    factors = []
    while i * i <= n:
        if n % i:
            i += 1
        else:
            n //= i
            factors.append(i)
    if n > 1:
        factors.append(n)
    return factors
44
Stefan

D'accord. Alors vous avez dit que vous comprenez les bases, mais vous n'êtes pas sûr exactement comment cela fonctionne. Tout d’abord, c’est une excellente réponse à la question du projet Euler dont il est issu. J'ai fait beaucoup de recherches sur ce problème et c'est de loin la réponse la plus simple.

Aux fins d’explication, je vais laisser n = 20. Pour exécuter le problème réel de Project Euler, laissez n = 600851475143.

n = 20 
i = 2

while i * i < n:
    while n%i == 0:
        n = n / i
    i = i + 1

print (n)

Cette explication utilise deux boucles while. La chose la plus importante à retenir à propos des boucles while est qu'elles fonctionnent jusqu'à ce qu'elles ne soient plus true

La boucle externe indique que si i * i n'est pas supérieur à n (car le facteur premier le plus grand ne sera jamais supérieur à la racine carrée de n), ajoutez 1 à i après l'exécution de la boucle interne. 

La boucle interne indique que, si i est divisé également en n, remplacez n par n divisé par i. Cette boucle s'exécute continuellement jusqu'à ce qu'elle ne soit plus vraie. Pour n=20 et i=2, n est remplacé par 10, puis à nouveau par 5. Étant donné que 2 ne se divise pas uniformément en 5, la boucle s'arrête avec n=5 et la boucle externe se termine, produisant ainsi i+1=3.

Enfin, étant donné que 3 carré est supérieur à 5, la boucle externe n'est plus true et affiche le résultat de n.

Merci d'avoir posté ceci. J'ai regardé le code pour toujours avant de réaliser comment cela fonctionnait exactement. J'espère que c'est ce que vous recherchez dans une réponse. Si non, faites le moi savoir et je peux expliquer plus loin.

26
Will Luce

On dirait que les gens font la même chose que Project Euler où vous codez vous-même la solution. Pour tous ceux qui souhaitent travailler, il existe le module primefac qui effectue très rapidement de très grands nombres:

#!python

import primefac
import sys

n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))
17
brian d foy

Pour la génération de nombres premiers, j'utilise toujours Sieve of Eratosthenes :

def primes(n):
    if n<=2:
        return []
    sieve=[True]*(n+1)
    for x in range(3,int(n**0.5)+1,2):
        for y in range(3,(n//x)+1,2):
            sieve[(x*y)]=False

    return [2]+[i for i in range(3,n,2) if sieve[i]]

In [42]: %timeit primes(10**5)
10 loops, best of 3: 60.4 ms per loop

In [43]: %timeit primes(10**6)
1 loops, best of 3: 1.01 s per loop

Vous pouvez utiliser Test de primalité Miller-Rabin pour vérifier si un nombre est premier ou non. Vous pouvez trouver ses implémentations Python ici .

Utilisez toujours timeit module pour chronométrer votre code, le second prend juste 15us:

def func():
    n = 600851475143
    i = 2
    while i * i < n:
         while n % i == 0:
            n = n / i
         i = i + 1

In [19]: %timeit func()
1000 loops, best of 3: 1.35 ms per loop

def func():
    i=1
    while i<100:i+=1
   ....:     

In [21]: %timeit func()
10000 loops, best of 3: 15.3 us per loop
7
Ashwini Chaudhary

Le plus grand facteur premier de 27 n'est pas 3 ?? Le code ci-dessus est peut-être le plus rapide, mais il échoue à 27 pas vrai? 27 = 3 * 3 * 3 Le code ci-dessus renvoie 1 Autant que je sache ..... 1 n'est ni premier ni composite

Je pense que c'est le meilleur code

def prime_factors(n):
    factors=[]
    d=2
    while(d*d<=n):
        while(n>1):            
            while n%d==0:
                factors.append(d)
                n=n/d
            d+=1
    return factors[-1]
7
m0rpheu5

Le code est incorrect avec 100. Il convient de vérifier le cas i * i = n: 

Je pense que cela devrait être:

while i * i <= n:
    if i * i = n:
        n = i
        break

    while n%i == 0:
        n = n / i
    i = i + 1

print (n)
3
quangpn88
def find_prime_facs(n):
  list_of_factors=[]
  i=2
  while n>1:
    if n%i==0:
      list_of_factors.append(i)
      n=n/i
      i=i-1
    i+=1  
  return list_of_factors
2
Perviz Mamedov

Une autre façon de faire ceci:

import sys
n = int(sys.argv[1])
result = []
for i in xrange(2,n):
    while n % i == 0:
        #print i,"|",n
        n = n/i
        result.append(i)

    if n == 1: 
        break

if n > 1: result.append(n)
print result

exemple de sortie:
python test.py 68
[2, 2, 17] 

2
Rajesh

Vous ne devriez pas faire de boucle jusqu'à la racine carrée du nombre! Cela peut être correct parfois, mais pas toujours!

Le plus grand facteur premier de 10 est 5, ce qui est supérieur au sqrt (10) (3,16, environ).

Le plus grand facteur premier de 33 est 11, ce qui est supérieur au sqrt (33) (5.5,74, environ).

Vous confondez cela avec la convenance selon laquelle, si un nombre a un facteur premier plus grand que son carré, il doit avoir au moins un autre facteur premier plus petit que son carré. Donc, avec vous voulez tester si un nombre est premier, il vous suffit de tester jusqu'à ce que son nombre.

0
rubslopes
"""
The prime factors of 13195 are 5, 7, 13 and 29.

What is the largest prime factor of the number 600851475143 ?

"""

from sympy import primefactors
print primefactors(600851475143)[-1]
0

Mon code:

# METHOD: PRIME FACTORS
def prime_factors(n):
    '''PRIME FACTORS: generates a list of prime factors for the number given
    RETURNS: number(being factored), list(prime factors), count(how many loops to find factors, for optimization)
    '''
    num = n                         #number at the end
    count = 0                       #optimization (to count iterations)
    index = 0                       #index (to test)
    t = [2, 3, 5, 7]                #list (to test)
    f = []                          #prime factors list
    while t[index] ** 2 <= n:
        count += 1                  #increment (how many loops to find factors)
        if len(t) == (index + 1):
            t.append(t[-2] + 6)     #extend test list (as much as needed) [2, 3, 5, 7, 11, 13...]
        if n % t[index]:            #if 0 does else (otherwise increments, or try next t[index])
            index += 1              #increment index
        else:
            n = n // t[index]       #drop max number we are testing... (this should drastically shorten the loops)
            f.append(t[index])      #append factor to list
    if n > 1:
        f.append(n)                 #add last factor...
    return num, f, f'count optimization: {count}'

Ce que j'ai comparé au code avec le plus de votes, ce qui était très rapide

    def prime_factors2(n):
        i = 2
        factors = []
        count = 0                           #added to test optimization
        while i * i <= n:
            count += 1                      #added to test optimization
            if n % i:
                i += 1
            else:
                n //= i
                factors.append(i)
        if n > 1:
            factors.append(n)
        return factors, f'count: {count}'   #print with (count added)

TESTING, (note, j'ai ajouté un COUNT dans chaque boucle pour tester l'optimisation)

# >>> prime_factors2(600851475143)
# ([71, 839, 1471, 6857], 'count: 1472')
# >>> prime_factors(600851475143)
# (600851475143, [71, 839, 1471, 6857], 'count optimization: 494')

Je pense que ce code pourrait être facilement modifié pour obtenir le (facteur le plus important) ou tout autre chose nécessaire. Je suis ouvert à toute question, mon objectif est d’améliorer cela beaucoup plus pour les facteurs premiers et les facteurs plus importants.

0
Dean Jones