簡體   English   中英

Python 尋找質因數

[英]Python Finding Prime Factors

兩部分問題:

  1. 試圖確定 600851475143 的最大質因數,我在網上發現這個程序似乎有效。 問題是,我很難弄清楚它到底是如何工作的,盡管我了解程序正在做什么的基礎知識。 另外,我希望您能闡明您可能知道的尋找主要因素的任何方法,也許無需測試每個數字,以及您的方法是如何工作的。

這是我在網上找到的素數分解代碼 [注意:此代碼不正確。 請參閱下面 Stefan 的回答以獲得更好的代碼。]

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

print(n)

#takes about ~0.01secs
  1. 為什么這段代碼比這段代碼快這么多,這只是為了測試速度,除此之外沒有其他真正目的?
i = 1
while i < 100:
    i += 1
#takes about ~3secs

這個問題是我在 google 上搜索"python prime factorization"時出現的第一個鏈接。 正如@quangpn88 所指出的,這個算法對於完美的平方是錯誤的(!) ,例如n = 4, 9, 16, ...但是,@quangpn88 的修復也不起作用,因為如果最大的素數,它會產生不正確的結果factor 出現 3 次或更多次,例如, n = 2*2*2 = 8n = 2*3*3*3 = 54

我相信 Python 中正確的蠻力算法是:

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

不要在性能代碼中使用它,但它可以用於中等數量的快速測試:

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

如果尋求完整的素數分解,這是蠻力算法:

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

行。 所以你說你了解基礎知識,但你不確定它是如何工作的。 首先,這是對它源自的 Project Euler 問題的一個很好的回答。 我對這個問題做了很多研究,這是迄今為止最簡單的回應。

出於解釋的目的,我讓n = 20 要運行真正的 Project Euler 問題,讓n = 600851475143

n = 20 
i = 2

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

print (n)

這個解釋使用了兩個while循環。 關於while循環的最重要的事情是它們會一直運行,直到它們不再為true為止。

外循環指出,雖然i * i不大於n (因為最大的質因子永遠不會大於n平方根),但在內循環運行后將i1

內部循環指出,當i平均分為n ,將n替換為n除以i 這個循環持續運行,直到它不再為真。 對於n=20i=2n替換為10 ,然后再次替換為5 因為2不能均勻地分成5 ,循環在n=5停止,外循環結束,產生i+1=3

最后,因為3 squared 大於5 ,所以外循環不再為true並打印出n的結果。

感謝您發布此信息。 在意識到它究竟是如何工作之前,我一直看着代碼。 希望這就是您在回復中尋找的內容。 如果沒有,請告訴我,我可以進一步解釋。

看起來人們正在做 Project Euler 的事情,你自己編寫解決方案。 對於其他想要完成工作的人,有一個primefac 模塊可以非常快速地處理非常大的數字:

#!python

import primefac
import sys

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

對於素數生成,我總是使用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

您可以使用Miller-Rabin 素數檢驗來檢查數字是否為素數。 您可以在此處找到它的 Python 實現。

始終使用timeit模塊為您的代碼計時,第二個只需要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

27 的最大質因數不是 3 嗎?? 上面的代碼可能是最快的,但它在 27 上失敗了,對嗎? 27 = 3*3*3 以上代碼返回 1 據我所知.....1 既不是質數也不是合數

我認為,這是更好的代碼

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

這樣做的另一種方法:

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

樣本輸出:
蟒蛇測試.py 68
[2, 2, 17]

如果您正在尋找維護良好的預先編寫的代碼,請使用來自SymPy的函數sympy.ntheory.primefactors

它返回n的素因數的排序列表。

>>> from sympy.ntheory import primefactors
>>> primefactors(6008)
[2, 751]

將列表傳遞給max()以獲得最大的質因數: max(primefactors(6008))

如果您想要n的質因數以及它們中的每一個的多重性,請使用sympy.ntheory.factorint

給定一個正整數nfactorint(n)返回一個字典,其中包含n的質因子作為鍵,它們各自的重數作為值。

>>> from sympy.ntheory import factorint
>>> factorint(6008)   # 6008 = (2**3) * (751**1)
{2: 3, 751: 1}

該代碼針對 Python 3.6.9 和 SymPy 1.1.1 進行了測試。

代碼錯誤為 100。它應該檢查 case i * i = n:

我覺得應該是:

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

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

print (n)

我的代碼:

# 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}'

我將其與得票最多的代碼進行了比較,速度非常快

    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)

測試,(注意,我在每個循環中添加了一個 COUNT 來測試優化)

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

我認為可以輕松修改此代碼以獲得(最大因素)或其他任何需要的代碼。 我對任何問題持開放態度,我的目標是對更大的質數和因數進行更多改進。

如果您想使用 numpy,這里有一種方法可以創建一個包含不大於 n 的所有素數的數組:

[ i for i in np.arange(2,n+1) if 0 not in np.array([i] * (i-2) ) % np.arange(2,i)]

看看這個,它可能對你的理解有所幫助。

#program to find the prime factors of a given number
import sympy as smp

try:
    number = int(input('Enter a number : '))
except(ValueError) :
    print('Please enter an integer !')
num = number
prime_factors = []
if smp.isprime(number) :
    prime_factors.append(number)
else :
    for i in range(2, int(number/2) + 1) :   
        """while figuring out prime factors of a given number, n
        keep in mind that a number can itself be prime or if not, 
        then all its prime factors will be less than or equal to its int(n/2 + 1)"""
        if smp.isprime(i) and number % i == 0 :
            while(number % i == 0) :
                prime_factors.append(i)
                number = number  / i
print('prime factors of ' + str(num) + ' - ')
for i in prime_factors :
    print(i, end = ' ')

在此處輸入圖片說明

這是我的 python 代碼:它可以快速檢查素數,並從最高到最低檢查素數。 如果沒有新的數字出來,你就必須停下來。 (對此有什么想法嗎?)

import math


def is_prime_v3(n):
    """ Return 'true' if n is a prime number, 'False' otherwise """
    if n == 1:
        return False

    if n > 2 and n % 2 == 0:
        return False

    max_divisor = math.floor(math.sqrt(n))
    for d in range(3, 1 + max_divisor, 2):
        if n % d == 0:
            return False
    return True


number = <Number>

for i in range(1,math.floor(number/2)):
    if is_prime_v3(i):
        if number % i == 0:
            print("Found: {} with factor {}".format(number / i, i))

最初問題的答案會在幾分之一秒內到達。

以下是兩種有效生成給定數的質因數的方法:

from math import sqrt


def prime_factors(num):
    '''
    This function collectes all prime factors of given number and prints them.
    '''
    prime_factors_list = []
    while num % 2 == 0:
        prime_factors_list.append(2)
        num /= 2
    for i in range(3, int(sqrt(num))+1, 2):
        if num % i == 0:
            prime_factors_list.append(i)
            num /= i
    if num > 2:
        prime_factors_list.append(int(num))
    print(sorted(prime_factors_list))


val = int(input('Enter number:'))
prime_factors(val)


def prime_factors_generator(num):
    '''
    This function creates a generator for prime factors of given number and generates the factors until user asks for them.
    It handles StopIteration if generator exhausted.
    '''
    while num % 2 == 0:
        yield 2
        num /= 2
    for i in range(3, int(sqrt(num))+1, 2):
        if num % i == 0:
            yield i
            num /= i
    if num > 2:
        yield int(num)


val = int(input('Enter number:'))
prime_gen = prime_factors_generator(val)
while True:
    try:
        print(next(prime_gen))
    except StopIteration:
        print('Generator exhausted...')
        break
    else:
        flag = input('Do you want next prime factor ? "y" or "n":')
        if flag == 'y':
            continue
        elif flag == 'n':
            break
        else:
            print('Please try again and enter a correct choice i.e. either y or n')

由於沒有人試圖用舊的 nice reduce方法來破解它,所以我要從事這個職業。 此方法對於此類問題並不靈活,因為它對參數數組執行重復操作的循環,並且默認情況下無法中斷此循環。 在我們為這樣的中斷循環實現我們自己的interupted reduce之后,門打開了:

from functools import reduce

def inner_func(func, cond, x, y):
    res = func(x, y)
    if not cond(res):
        raise StopIteration(x, y)
    return res

def ireducewhile(func, cond, iterable):
    # generates intermediary results of args while reducing
    iterable = iter(iterable)
    x = next(iterable)
    yield x
    for y in iterable:
        try:
            x = inner_func(func, cond, x, y)
        except StopIteration:
            break
        yield x

之后我們就可以使用一些與標准 Python reduce 方法的輸入相同的func 讓這個func以下列方式定義:

def division(c):
    num, start = c
    for i in range(start, int(num**0.5)+1):
        if num % i == 0:
            return (num//i, i)
    return None

假設我們要對一個數 600851475143 進行因式分解,重復使用該函數后該函數的預期輸出應該是這樣的:

(600851475143, 2) -> (8462696833 -> 71), (10086647 -> 839), (6857, 1471) -> None

元組的第一項是division方法所取的數字,並嘗試除以最小的除數,從第二項開始,以該數字的平方根結束。 如果不存在除數,則返回 None。 現在我們需要從這樣定義的迭代器開始:

def gener(prime):
    # returns and infinite generator (600851475143, 2), 0, 0, 0...
    yield (prime, 2)
    while True:
        yield 0

最后,循環的結果是:

result = list(ireducewhile(lambda x,y: div(x), lambda x: x is not None, iterable=gen(600851475143)))
#result: [(600851475143, 2), (8462696833, 71), (10086647, 839), (6857, 1471)]

輸出質數除數可以通過以下方式捕獲:

if len(result) == 1: output = result[0][0]
else: output = list(map(lambda x: x[1], result[1:]))+[result[-1][0]]
#output: [2, 71, 839, 1471]

筆記:

為了提高效率,您可能希望使用位於特定范圍內的預生成素數,而不是該范圍內的所有值。

你不應該循環到數字的平方根! 有時可能是對的,但並非總是如此!

10 的最大質因數是 5,比 sqrt(10) (3.16, aprox) 大。

33 的最大質因數是 11,比 sqrt(33) (5.5,74, aprox) 大。

您將此與適當性混淆了,即如果一個數字的質因數大於其 sqrt,則它必須至少有另一個小於其 sqrt 的質因數。 所以,如果你想測試一個數字是否是素數,你只需要測試直到它的 sqrt。

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

def primefactors():
    m=int(input('enter the number:'))
    for i in range(2,m):
        if (prime(i)):
            if m%i==0:
                print(i)
    return print('end of it')

primefactors()

處理 2 后跳過偶數的另一種方法:

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

  return factors
n=int(input("Enter the number"))
if n==1 :  #because the below logic doesn't work on 1
    print(n)
for i in range(2 , n+1):
    if n%i==0 :
        n1=i  #get factor
        for b in range(2,n+1): #check if it is prime
            if ((n1%b)==0) & (n1==b):
                print(n1)
            elif (n1%b)==0 or n1<b:  #if not then pass
                break

我確信這是最糟糕的邏輯,但這是我在 .py 中擁有的所有知識,該程序將從用戶那里獲得一個數字並打印所有的因數,這些數字是 12 的素數,它將給出 2,3

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM