Python'da bir sayının tüm faktörlerini bulmanın en etkili yolu nedir?


142

Birisi bana Python'da bir sayının tüm faktörlerini bulmanın etkili bir yolunu açıklayabilir mi (2.7)?

Bunu yapmak için bir algoritma oluşturabilirim, ancak bence kötü kodlanmış ve çok sayıda sonuç elde etmek çok uzun sürüyor.


3
Python bilmiyorum. Ama bu sayfa sizin için yararlı olabilir en.wikipedia.org/wiki/Integer_factorization
Stan

3
Kullanmaya ne dersiniz primefac? pypi.python.org/pypi/primefac
Zubo

Yanıtlar:


265
from functools import reduce

def factors(n):    
    return set(reduce(list.__add__, 
                ([i, n//i] for i in range(1, int(n**0.5) + 1) if n % i == 0)))

Bu, tüm faktörleri çok hızlı bir şekilde döndürecektir. n .

Neden üst sınır olarak karekök?

sqrt(x) * sqrt(x) = x. Eğer iki faktör aynı ise, ikisi de kareköktür. Bir faktörü büyütürseniz, diğer faktörü küçültmelisiniz. Bu, ikisinden birinin her zaman eşit veya daha az olacağı anlamına gelir sqrt(x), bu nedenle iki eşleşen faktörden birini bulmak için o noktaya kadar arama yapmanız gerekir. Sonra x / fac1almak için kullanabilirsinizfac2 .

reduce(list.__add__, ...)Küçük listeleri alıyor[fac1, fac2] ve bir uzun listede birbirine birleştirir.

Daha küçük [i, n/i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0olana bölündüğünüzde geri kalan kısım nsıfırsa bir çift faktör döndürür (daha büyük olanı da kontrol etmesine gerek yoktur; sadece daha nküçük olana bölerek alır .)

set(...)Dışarıdan sadece mükemmel kareler için olur çiftleri, kurtuluyor. Çünkü n = 4, bu 2iki kez geri döner , bu yüzden setonlardan birinden kurtulur.


1
Bunu bilgisayarımdaki bir algoritma listesinden kopyaladım, yaptığım tek şey kapsüllenmişti sqrt- muhtemelen insanlar gerçekten Python 3'ü desteklemeyi düşünmeden önceydi. Sanırım aldığım site denedim __iadd__ve daha hızlıydı . Yine de bir noktadan x**0.5daha hızlı olma hakkında bir şeyler hatırlıyorum sqrt(x)- ve bu şekilde daha kusursuz.
agf

7
if not n % iBunun yerine kullanırsam% 15 daha hızlı performans gösteririf n % i == 0
dansalmo

3
Biz bir tamsayı değil, bir şamandıra dönmek istiyorum @sthzg ve Python 3 /hem argümanlar tam sayılardır ve bunlar, yani tam DIVISABLE bile bir float dönecektir 4 / 2 == 2.0değil 2.
agf

7
Bunun eski bir soru olduğunu biliyorum, ancak Python 3.x'te from functools import reducebu işi yapmak için eklemeniz gerekiyor .
anonymoose

5
@ unseen_rider: Kulağa doğru gelmiyor. Yedeklemek için herhangi bir şey sağlayabilir misiniz?
Ry-

55

@Agf tarafından sunulan çözüm harika, ancak keyfi bir oran için ~% 50 daha hızlı çalışma süresi elde edilebilir parite kontrol edilerek sayı . Tek bir sayının faktörleri her zaman garip olduğundan, tek sayılarla uğraşırken bunları kontrol etmek gerekli değildir.

Project Euler bulmacalarını kendim çözmeye başladım. Bazı problemlerde, iki iç içe fordöngü içinde bir bölücü kontrolü çağrılır ve bu nedenle bu fonksiyonun performansı önemlidir.

Bu gerçeği agf'ın mükemmel çözümü ile birleştirerek, bu fonksiyonla sonuçlandım:

from math import sqrt
def factors(n):
        step = 2 if n%2 else 1
        return set(reduce(list.__add__,
                    ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

Ancak, küçük sayılarda (~ <100), bu değişiklikten kaynaklanan ek yük, işlevin daha uzun sürmesine neden olabilir.

Hızı kontrol etmek için bazı testler yaptım. Kullanılan kod aşağıdadır. Farklı araziler üretmek için, X = range(1,100,1)buna göre değiştim .

import timeit
from math import sqrt
from matplotlib.pyplot import plot, legend, show

def factors_1(n):
    step = 2 if n%2 else 1
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n))+1, step) if n % i == 0)))

def factors_2(n):
    return set(reduce(list.__add__,
                ([i, n//i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0)))

X = range(1,100000,1000)
Y = []
for i in X:
    f_1 = timeit.timeit('factors_1({})'.format(i), setup='from __main__ import factors_1', number=10000)
    f_2 = timeit.timeit('factors_2({})'.format(i), setup='from __main__ import factors_2', number=10000)
    Y.append(f_1/f_2)
plot(X,Y, label='Running time with/without parity check')
legend()
show()

X = aralık (1.100,1) X = aralık (1.100,1)

Burada önemli bir fark yok, ancak daha büyük sayılarla avantaj açıktır:

X = aralık (1.100000,1000) (yalnızca tek sayılar) X = aralık (1.100000,1000) (yalnızca tek sayılar)

X = aralık (2.100000,100) (yalnızca çift sayılar) X = aralık (2.100000,100) (yalnızca çift sayılar)

X = aralık (1.100000.1001) (alternatif parite) X = aralık (1.100000.1001) (alternatif parite)


28

agf'ın cevabı gerçekten çok havalı. Kullanmamak için yeniden yazıp yazamayacağımı görmek istedim reduce(). Ben geldi budur:

import itertools
flatten_iter = itertools.chain.from_iterable
def factors(n):
    return set(flatten_iter((i, n//i) 
                for i in range(1, int(n**0.5)+1) if n % i == 0))

Ayrıca zor jeneratör işlevlerini kullanan bir sürümünü denedim:

def factors(n):
    return set(x for tup in ([i, n//i] 
                for i in range(1, int(n**0.5)+1) if n % i == 0) for x in tup)

Ben hesaplayarak zamanladım:

start = 10000000
end = start + 40000
for n in range(start, end):
    factors(n)

Python'un derlemesine izin vermek için bir kez koştum, sonra üç kez time (1) komutunun altında koştum ve en iyi zamanı korudum.

  • sürümü azalt: 11.58 saniye
  • itertools sürümü: 11.49 saniye
  • zor sürüm: 11.12 saniye

İtertools sürümünün bir demet oluşturduğunu ve flatten_iter () öğesine ilettiğini unutmayın. Bir liste oluşturmak için kodu değiştirirseniz, biraz yavaşlar:

  • iterools (liste) sürümü: 11.62 saniye

Zor jeneratör işlevleri sürümü Python mümkün olan en hızlı olduğuna inanıyorum. Ancak, indirgeme versiyonundan çok daha hızlı değil, ölçümlerime dayanarak yaklaşık% 4 daha hızlı.


2
"zor sürümü" basitleştirmek olabilir (gereksiz kaldırmak for tup in):factors = lambda n: {f for i in range(1, int(n**0.5)+1) if n % i == 0 for f in [i, n//i]}
jfs

11

Agf'ın cevabına alternatif bir yaklaşım:

def factors(n):    
    result = set()
    for i in range(1, int(n ** 0.5) + 1):
        div, mod = divmod(n, i)
        if mod == 0:
            result |= {i, div}
    return result

1
Div mod modunu açıklayabilir misiniz?
Adnan

3
divmod (x, y), ((xx% y) / y, x% y), yani bölümün bölümü ve kalanını döndürür.
c4757p

Bu yinelenen faktörleri iyi işlemez - örneğin 81'i deneyin.
phkahler

Cevabınız daha açık, bu yüzden yanlış anlamaya yetecek kadar şey bulabildim. Birden fazla 3'ü çağırmak istediğiniz asal çarpanlara ayırmayı düşünüyordum. OP'nin istediği gibi, bu iyi olmalı.
phkahler

Her şeyi tek bir satıra yığtım çünkü agf'ın cevabı bunu yaptı. reduce()Önemli ölçüde daha hızlı olup olmadığını görmekle ilgileniyordum , bu yüzden reduce()agf'ın yaptığı gibi hemen hemen her şeyi yaptım. Okunabilirlik için, gibi is_even(n)bir ifade yerine bir işlev çağrısı görmek güzel olurdu n % 2 == 0.
steveha

9

İşte aynı algoritmayı daha pitonik bir tarzda uygulayan @ agf çözümüne bir alternatif:

def factors(n):
    return set(
        factor for i in range(1, int(n**0.5) + 1) if n % i == 0
        for factor in (i, n//i)
    )

Bu çözüm hem Python 2 hem de Python 3'te içe aktarma olmadan çalışır ve çok daha okunabilir. Bu yaklaşımın performansını test etmedim, ancak asimptotik olarak aynı olmalı ve performans ciddi bir endişe ise, her iki çözüm de optimal değildir.


7

SymPy'de factorint adı verilen bir endüstri gücü algoritması vardır :

>>> from sympy import factorint
>>> factorint(2**70 + 3**80) 
{5: 2,
 41: 1,
 101: 1,
 181: 1,
 821: 1,
 1597: 1,
 5393: 1,
 27188665321L: 1,
 41030818561L: 1}

Bu bir dakikadan az sürdü. Bir yöntem kokteyli arasında geçiş yapar. Yukarıda bağlantılı belgelere bakın.

Tüm asal faktörler göz önüne alındığında, diğer tüm faktörler kolayca oluşturulabilir.


Kabul edilen cevap, yukarıdaki sayıyı hesaba katacak kadar uzun süre (yani bir sonsuzluk) çalışmasına izin verilse bile, bazı büyük sayılar için başarısız olacaktır, örneğin aşağıdaki örnek. Bu özensizlikten kaynaklanıyor int(n**0.5). Örneğin, n = 10000000000000079**2biz var

>>> int(n**0.5)
10000000000000078L

Yana 10000000000000079 bir asal kabul cevabım algoritması bu faktör asla bulamayacağım. Bunun sadece birer birer olmadığını unutmayın; daha büyük sayılar için daha fazla kapalı olacaktır. Bu nedenle, bu tür algoritmalarda kayan nokta sayılarından kaçınmak daha iyidir.


2
Tüm bölenleri değil, sadece asal faktörleri bu yüzden gerçekten bir cevap değil. Diğer tüm faktörlerin nasıl oluşturulabileceğini göstermelisiniz, sadece kolay olduğunu söylemeyin! Bu arada, sympy.divisors bu soruyu cevaplamak için daha iyi bir eşleşme olabilir.
Colin Pitrat

Ve sympy.divisors'ın kabul edilen çözümden çok daha hızlı olmadığını unutmayın.
Colin Pitrat

@ColinPitrat: sympy.divisorsÖzellikle birkaç böleni olan sayılar için çok daha hızlı olmayan bir şüphe . Kriterleriniz var mı?
Ry-

@Bu yorumu bir yıl önce yazdığımda bir tane yaptım. Birini yazmak 2 dakika sürer, bu yüzden çift kontrol etmekten çekinmeyin.
Colin Pitrat

3
@ColinPitrat: Kontrol edildi. Beklendiği gibi, kabul edilen cevap sympy.divisors100.000 ile aynı hızda ve daha yüksek her şey için (hız gerçekten önemli olduğunda) daha yavaştır. (Ve elbette, sympy.divisorssayılar üzerinde çalışır 10000000000000079**2.)
Ry-

7

10 ** 16'ya kadar (belki biraz daha fazla) n için, işte hızlı saf bir Python 3.6 çözümü,

from itertools import compress

def primes(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def factorization(n):
    """ Returns a list of the prime factorization of n """
    pf = []
    for p in primeslist:
      if p*p > n : break
      count = 0
      while not n % p:
        n //= p
        count += 1
      if count > 0: pf.append((p, count))
    if n > 1: pf.append((n, 1))
    return pf

def divisors(n):
    """ Returns an unsorted list of the divisors of n """
    divs = [1]
    for p, e in factorization(n):
        divs += [x*p**k for k in range(1,e+1) for x in divs]
    return divs

n = 600851475143
primeslist = primes(int(n**0.5)+1) 
print(divisors(n))

6

Afg & eryksun'un çözümünde daha fazla gelişme. Aşağıdaki kod parçası, çalışma süresi asimptotik karmaşıklığını değiştirmeden tüm faktörlerin sıralanmış bir listesini döndürür:

    def factors(n):    
        l1, l2 = [], []
        for i in range(1, int(n ** 0.5) + 1):
            q,r = n//i, n%i     # Alter: divmod() fn can be used.
            if r == 0:
                l1.append(i) 
                l2.append(q)    # q's obtained are decreasing.
        if l1[-1] == l2[-1]:    # To avoid duplication of the possible factor sqrt(n)
            l1.pop()
        l2.reverse()
        return l1 + l2

Fikir: nlog (n) karmaşıklığı veren sıralı bir liste almak için list.sort () işlevini kullanmak yerine; O (n) karmaşıklığını alan l2'de list.reverse () kullanmak çok daha hızlıdır. (Python bu şekilde yapılır.) L2.reverse () yönteminden sonra, sıralanan faktör listesini almak için l1 eklenebilir.

Dikkat, l1 artan i -s içerir . l2 azalan q -s içerir . Yukarıdaki fikri kullanmanın ardındaki sebep budur.


Kesinlikle list.reverseO (n) O (1) değil, genel karmaşıklığı değiştirdiğinden değil.
agf

Evet bu doğru. Bir hata yaptım. O (n) olmalıdır. (Cevabı şimdi doğru
olana

@ Steveha veya @ agf çözümlerinden yaklaşık 2 kat daha yavaştır.
jfs

l1 + l2.reversed()Listeyi tersine çevirmek yerine geri dönerek küçük (% 2-3) bir hız artışı elde edebilirsiniz .
Rakurai

6

Bu harika cevapların çoğunu verimlilikleri ile basit fonksiyonumu karşılaştırmak için timeit ile denedim ve yine de burada listelenenlerin daha iyi performans gösterdiğini görüyorum. Paylaşacağım ve hepinizin ne düşündüğünü anlayacağımı düşündüm.

def factors(n):
    results = set()
    for i in xrange(1, int(math.sqrt(n)) + 1):
        if n % i == 0:
            results.add(i)
            results.add(int(n/i))
    return results

Yazıldığı gibi, test etmek için matematiği içe aktarmanız gerekir, ancak math.sqrt (n) yerine n **. 5 yerine da çalışılmalıdır. Yinelenenleri ne olursa olsun bir kümede var olamaz çünkü yinelenenleri kontrol etmek için zaman israf etmeyin.


Harika şeyler! İnt (math.sqrt (n)) + 1 öğesini for döngüsünün dışına koyarsanız, for döngüsünün her yinelemesini yeniden hesaplamak zorunda kalmayacağınızdan, bundan biraz daha fazla performans elde etmelisiniz
Tristan Forward

3
@TristanForward: Python'da döngüler için böyle çalışmaz. xrange(1, int(math.sqrt(n)) + 1)bir kez değerlendirilir.
Ry-

5

İşte büyük sayılarla iyi performans gösteren bir başka alternatif. Bu kullandığı sumlisteyi düzleştirmek.

def factors(n):
    return set(sum([[i, n//i] for i in xrange(1, int(n**0.5)+1) if not n%i], []))

1
Bu olmaz, gereksiz yere ikinci dereceden bir zamandır. Bir listeyi düzleştirmek için sumveya kullanmayın reduce(list.__add__).
juanpa.arrivillaga

5

Bir sayının faktörlerini bulmanın en basit yolu:

def factors(x):
    return [i for i in range(1,x+1) if x%i==0]

4

sqrt(number_to_factor)3 * 3 * 11 ve gibi 99 gibi alışılmadık sayılardan daha büyük sayıyı yakaladığınızdan emin olun floor sqrt(99)+1 == 10.

import math

def factor(x):
  if x == 0 or x == 1:
    return None
  res = []
  for i in range(2,int(math.floor(math.sqrt(x)+1))):
    while x % i == 0:
      x /= i
      res.append(i)
  if x != 1: # Unusual numbers
    res.append(x)
  return res

1
Bir sayının tüm faktörlerini üretmez. Bir sayının asal faktörlerini hesaplar, örneğin, x=8beklenen:, [1, 2, 4, 8]var:[2, 2, 2]
jfs

@Agf tarafından verilen koda 9 girdiğinde 11 bulunur. `i = 9 ->% 99 9 == 0 -> 9 ve 99/9 = 11 eklenmiştir.
Steinar Lima

2

Çok daha hızlı gitmek için asal sayıları kullanmak istiyorsanız bir örnek. Bu listelerin internette bulunması kolaydır. Kodda yorumlar ekledim.

# http://primes.utm.edu/lists/small/10000.txt
# First 10000 primes

_PRIMES = (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, 103, 107, 109, 113, 
        127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 
        179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 
        233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 
        283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 
        353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 
        419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 
        467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 
        547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 
        607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 
        661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 
        739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 
        811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 
        877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 
        947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 
# Mising a lot of primes for the purpose of the example
)


from bisect import bisect_left as _bisect_left
from math import sqrt as _sqrt


def get_factors(n):
    assert isinstance(n, int), "n must be an integer."
    assert n > 0, "n must be greather than zero."
    limit = pow(_PRIMES[-1], 2)
    assert n <= limit, "n is greather then the limit of {0}".format(limit)
    result = set((1, n))
    root = int(_sqrt(n))
    primes = [t for t in get_primes_smaller_than(root + 1) if not n % t]
    result.update(primes)  # Add all the primes factors less or equal to root square
    for t in primes:
        result.update(get_factors(n/t))  # Add all the factors associted for the primes by using the same process
    return sorted(result)


def get_primes_smaller_than(n):
    return _PRIMES[:_bisect_left(_PRIMES, n)]


2

potansiyel olarak daha etkin bir algoritma (burada küçük asal faktörler varsa n). Buradaki hile, asal faktörlerin her bulunuşunda deneme bölümünün gerekli olduğu limiti ayarlamaktır :

def factors(n):
    '''
    return prime factors and multiplicity of n
    n = p0^e0 * p1^e1 * ... * pk^ek encoded as
    res = [(p0, e0), (p1, e1), ..., (pk, ek)]
    '''

    res = []

    # get rid of all the factors of 2 using bit shifts
    mult = 0
    while not n & 1:
        mult += 1
        n >>= 1
    if mult != 0:
        res.append((2, mult))

    limit = round(sqrt(n))
    test_prime = 3
    while test_prime <= limit:
        mult = 0
        while n % test_prime == 0:
            mult += 1
            n //= test_prime
        if mult != 0:
            res.append((test_prime, mult))
            if n == 1:              # only useful if ek >= 3 (ek: multiplicity
                break               # of the last prime) 
            limit = round(sqrt(n))  # adjust the limit
        test_prime += 2             # will often not be prime...
    if n != 1:
        res.append((n, 1))
    return res

bu elbette hala deneme bölümü ve daha süslü bir şey değil. bu nedenle verimliliğinde hala çok sınırlıdır (özellikle küçük bölenleri olmayan büyük sayılar için).

bu python3; bölme// , python 2 (ekleme from __future__ import division) için uyarlamanız gereken tek şey olmalıdır .


1

Kullanmak set(...)kodu biraz yavaşlatır ve yalnızca kare kökü kontrol ettiğinizde gerçekten gereklidir. İşte benim versiyonum:

def factors(num):
    if (num == 1 or num == 0):
        return []
    f = [1]
    sq = int(math.sqrt(num))
    for i in range(2, sq):
        if num % i == 0:
            f.append(i)
            f.append(num/i)
    if sq > 1 and num % sq == 0:
        f.append(sq)
        if sq*sq != num:
            f.append(num/sq)
    return f

if sq*sq != num:Karekök bir tamsayı değil, kare kökünün kat bir etken olduğu durum, 12, gibi numaralar için gereklidir.

Bu sürümün numaranın kendisini döndürmediğini, ancak isterseniz kolay bir düzeltme olduğunu unutmayın. Çıktı da sıralanmamış.

1-200 arasındaki tüm sayılar için 10000 kez ve 1-5000 arasındaki tüm sayılar için 100 kez zamanlama yaptım. Dansalmo, Jason Schorn, oxrock, agf, steveha ve eryksun'un çözümleri de dahil olmak üzere test ettiğim diğer tüm versiyonlardan daha iyi performans gösteriyor, ancak oxrock'lar çok daha yakın.


1

maksimum faktörünüz numaranızdan fazla değil, diyelim ki

def factors(n):
    factors = []
    for i in range(1, n//2+1):
        if n % i == 0:
            factors.append (i)
    factors.append(n)

    return factors

voila!


1
 import math

    '''
    I applied finding prime factorization to solve this. (Trial Division)
    It's not complicated
    '''


    def generate_factors(n):
        lower_bound_check = int(math.sqrt(n))  # determine lowest bound divisor range [16 = 4]
        factors = set()  # store factors
        for divisors in range(1, lower_bound_check + 1):  # loop [1 .. 4]
            if n % divisors == 0:
                factors.add(divisors)  # lower bound divisor is found 16 [ 1, 2, 4]
                factors.add(n // divisors)  # get upper divisor from lower [ 16 / 1 = 16, 16 / 2 = 8, 16 / 4 = 4]
        return factors  # [1, 2, 4, 8 16]


    print(generate_factors(12)) # {1, 2, 3, 4, 6, 12} -> pycharm output

 Pierre Vriens hopefully this makes more sense. this is an O(nlogn) solution. 

0

Aşağıdaki liste kavrayışı kadar basit bir şey kullanın, 1'i test etmeye ihtiyacımız olmadığını ve bulmaya çalıştığımız sayıyı not edin:

def factors(n):
    return [x for x in range(2, n//2+1) if n%x == 0]

Karekökü kullanımına referans olarak, in 10. faktörlerinin tamsayı kısmını bulmak istediğinizi sqrt(10) = 4dolayısıylarange(1, int(sqrt(10))) = [1, 2, 3, 4] ve 4 açıkça 5. özlüyor kadar test.

Bir şeyi kaçırmadıkça önerebileceğim, eğer böyle yapmak zorundaysan kullanıyorsun int(ceil(sqrt(x))). Tabii ki bu, işlevlere birçok gereksiz çağrı üretir.


Bu çözümün sorunu, muhtemelen faktör olamayacak birçok sayıyı kontrol etmesidir - ve faktör çiftinin daha küçük olduğunu bulduktan sonra bir faktör olduğunu zaten bildiğinizde, her bir faktör çiftinin yüksekliğini ayrı ayrı kontrol eder.
agf

1
@ JasonSchorn: 2 bulduğunuzda, 10/2 = 5'in de bir bölen olduğunu hemen biliyorsunuz, 5'i ayrı ayrı kontrol etmeye gerek yok! :)
Moberg

0

Okunabilirlik ve hız @ oxrock'un çözümü için en iyisi olduğunu düşünüyorum, bu yüzden python 3+ için yeniden yazılan kod:

def num_factors(n):
    results = set()
    for i in range(1, int(n**0.5) + 1):
        if n % i == 0: results.update([i,int(n/i)])
    return results

0

Bu soruyu gördüğümde, numpy'nin python döngülerinden çok daha hızlı olduğu halde kimsenin numpy kullanmadığını görünce çok şaşırdım . @ Agf'ın çözümünü numpy ile uygulayarak ortalama 8 kat daha hızlı çıktı . İnanıyorum ki diğer bazı çözümleri numpy ile uygularsanız harika zamanlar geçirebilirsiniz.

İşte benim işlevi:

import numpy as np
def b(n):
    r = np.arange(1, int(n ** 0.5) + 1)
    x = r[np.mod(n, r) == 0]
    return set(np.concatenate((x, n / x), axis=None))   

X ekseni sayılarının işlevlere giriş olmadığına dikkat edin. Fonksiyonlara giriş, x ekseni eksi 1'deki sayıya 2'dir. Böylece, onun olduğu yerde giriş 2 ** 10-1 = 1023 olacaktır.

Döngüler yerine numpy kullanımı performans testi sonuçları.


1
Bir kütüphane kullanacaksanız, onu doğru olan da yapabilirsiniz: Evgeni Sergeev'in cevabında görüldüğü gibi SymPy.
Ry-

0
import 'dart:math';
generateFactorsOfN(N){
  //determine lowest bound divisor range
  final lowerBoundCheck = sqrt(N).toInt();
  var factors = Set<int>(); //stores factors
  /**
   * Lets take 16:
   * 4 = sqrt(16)
   * start from 1 ...  4 inclusive
   * check mod 16 % 1 == 0?  set[1, (16 / 1)]
   * check mod 16 % 2 == 0?  set[1, (16 / 1) , 2 , (16 / 2)]
   * check mod 16 % 3 == 0?  set[1, (16 / 1) , 2 , (16 / 2)] -> unchanged
   * check mod 16 % 4 == 0?  set[1, (16 / 1) , 2 , (16 / 2), 4, (16 / 4)]
   *
   *  ******************* set is used to remove duplicate
   *  ******************* case 4 and (16 / 4) both equal to 4
   *  return factor set<int>.. this isn't ordered
   */

  for(var divisor = 1; divisor <= lowerBoundCheck; divisor++){
    if(N % divisor == 0){
      factors.add(divisor);
      factors.add(N ~/ divisor); // ~/ integer division 
    }
  }
  return factors;
}

Buradaki algoritmanın neredeyse tamamı, * .5 sayısıyla sınırlıdır, ancak aslında bu aralık çok daha küçüktür. aslında sayının sqrt. Eğer alt bölen varsa, onu kolayca üst bölen alabiliriz. onun sadece sayı / bölen beri. 16 için sqrt için 4 olsun, sonra 1'den 4'e döngü. 2 16 alt sınır bölen olduğundan 8 almak için 16/2 alır. 1 varsa 16 o zaman 16 almak (16/1). Başbakan çarpanlarına ayırma hakkında öğrenirken bunu buldum, bu yüzden başka bir yerde yayınlanıp yayınlanmadığını bilmiyorum, ama çok sayıda bile çalışıyor. Bir python çözümü sağlayabilirim.
Tangang Atanga

-4

Bunu yapmanın en basit yolu olduğunu düşünüyorum:

    x = 23

    i = 1
    while i <= x:
      if x % i == 0:
        print("factor: %s"% i)
      i += 1

Cevabınız doğru sonucu verirken çok verimsiz. Kabul edilen cevaba bir göz atın. Sorunu nasıl çözdüğünün açıklaması her zaman bir cevabın daha kullanışlı olmasına yardımcı olur.
Nick
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.