파이썬에서 숫자의 모든 요소를 ​​찾는 가장 효율적인 방법은 무엇입니까?


142

누군가 파이썬 (2.7)에서 숫자의 모든 요인을 찾는 효율적인 방법을 설명해 줄 수 있습니까?

이 작업을 수행하는 알고리즘을 만들 수는 있지만 코딩이 잘못되어 많은 수의 결과를 생성하는 데 너무 오래 걸린다고 생각합니다.


3
나는 파이썬을 모른다. 그러나이 페이지는 당신에게 유용 할 것입니다 en.wikipedia.org/wiki/Integer_factorization
Stan

3
어때요 primefac? pypi.python.org/pypi/primefac
Zubo

답변:


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)))

이렇게하면 모든 요소를 ​​매우 신속하게 숫자로 반환합니다 n.

왜 제곱근이 상한값입니까?

sqrt(x) * sqrt(x) = x. 두 요소가 같으면 모두 제곱근입니다. 한 요소를 더 크게 만들면 다른 요소를 더 작게 만들어야합니다. 이것은 둘 중 하나가 항상보다 작거나 같다는 것을 의미 sqrt(x)하므로 두 개의 일치하는 요소 중 하나를 찾으려면 해당 지점까지만 검색하면됩니다. 그런 다음을 사용 x / fac1하여 얻을 수 fac2있습니다.

reduce(list.__add__, ...)의 작은 목록을 가지고있다 [fac1, fac2]하나 개의 긴 목록에 함께 합류.

[i, n/i] for i in range(1, int(sqrt(n)) + 1) if n % i == 0반환 요인의 한 쌍은 분할 나머지 경우 n작은 하나는 제로 (너무 큰 하나를 체크 할 필요가 없습니다, 그냥 가져가 나누어 n하나의 작은으로.)

set(...)외부에은 완벽한 사각형을 위해 발생하는 중복, 제거지고 있습니다. 의 경우 n = 4이것은 2두 번 반환 되므로 set그중 하나를 제거합니다.


1
필자는 이것을 컴퓨터의 알고리즘 목록에서 복사하여 붙여 넣었습니다. 캡슐화하는 sqrt것만으로 사람들이 실제로 Python 3 지원에 대해 생각하기 전일 __iadd__것입니다. . 나는 어느 시점 x**0.5보다 빠르다는 것에 대해 무언가를 기억하는 것 같습니다 sqrt(x).
agf

7
내가 if not n % i대신 사용하면 15 % 더 빠른 것 같습니다if n % i == 0
dansalmo

3
우리는이 정수가 아닌 float를 반환 할 @sthzg, 파이썬 3에 /두 인수가 정수 그들은 즉, 정확히 divisable 경우에도 float를 반환 4 / 2 == 2.0하지 2.
agf

7
나는 이것이 오래된 질문이라는 것을 알고 있지만 Python 3.x에서는 from functools import reduce이 작업을 수행하기 위해 추가해야합니다 .
anonymoose

5
@unseen_rider : 그 말이 맞지 않습니다. 백업 할 내용을 제공 할 수 있습니까?
Ry-

55

@agf가 제시하는 솔루션은 훌륭하지만 패리티를 검사 하여 임의의 홀수에 대해 ~ 50 % 더 빠른 실행 시간을 달성 할 수 있습니다 . 홀수의 인자는 항상 홀수이므로 홀수를 처리 할 때이를 확인할 필요는 없습니다.

방금 Project Euler 퍼즐을 스스로 풀기 시작했습니다 . 어떤 문제에서는 두 개의 중첩 for루프 내에서 제수 검사가 호출되므로이 기능의 성능이 필수적입니다.

이 사실을 agf의 우수한 솔루션과 결합 하여이 기능을 사용했습니다.

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)))

그러나 작은 숫자 (~ <100)에서는이 변경으로 인한 추가 오버 헤드로 인해 기능이 더 오래 걸릴 수 있습니다.

속도를 확인하기 위해 몇 가지 테스트를 실행했습니다. 아래는 사용 된 코드입니다. 다른 음모를 만들기 위해 X = range(1,100,1)그에 따라 변경했습니다 .

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 = 범위 (1,100,1) X = 범위 (1,100,1)

여기서 큰 차이는 없지만 숫자가 클수록 이점이 분명합니다.

X = 범위 (1,100000,1000) (홀수 만) X = 범위 (1,100000,1000) (홀수 만)

X = 범위 (2,100000,100) (짝수 만) X = 범위 (2,100000,100) (짝수 만)

X = 범위 (1,100000,1001) (대체 패리티) X = 범위 (1,100000,1001) (대체 패리티)


28

agf의 답변은 정말 멋지다. 사용하지 않기 위해 다시 작성할 수 있는지 확인하고 싶었습니다 reduce(). 이것이 내가 생각해 낸 것입니다.

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))

또한 까다로운 생성기 기능을 사용하는 버전을 시도했습니다.

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)

나는 그것을 계산하여 시간을 정했다.

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

파이썬이 컴파일하도록 한 번 실행 한 다음 time (1) 명령으로 세 번 실행하여 최상의 시간을 유지했습니다.

  • 버전 축소 : 11.58 초
  • itertools 버전 : 11.49 초
  • 까다로운 버전 : 11.12 초

itertools 버전은 튜플을 빌드하고 flatten_iter ()에 전달합니다. 대신 목록을 작성하도록 코드를 변경하면 약간 느려집니다.

  • iterools (목록) 버전 : 11.62 초

나는 까다로운 생성기 함수 버전이 파이썬에서 가장 빠르다고 생각합니다. 그러나 감소 버전보다 훨씬 빠르지는 않습니다. 측정에 따라 약 4 % 빠릅니다.


2
당신은 "까다로운 버전을"단순화 수 (불필요한 제거 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의 답변에 대한 다른 접근법 :

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 부분을 설명 할 수 있습니까?
Adnan

3
divmod (x, y)는 ((xx % y) / y, x % y), 즉 몫과 나머지 부분을 반환합니다.
c4757p

이것은 중복 요소를 잘 처리하지 못합니다-예를 들어 81을 시도하십시오.
phkahler

당신의 대답은 더 명확하므로 오해하기에 충분합니다. 여러 개의 3을 불러 내고자하는 주요 인수 분해를 생각하고있었습니다. 이것은 OP가 요구 한 것이므로 괜찮습니다.
phkahler

agf의 답변이 그렇게했기 때문에 모든 것을 한 줄에 쌓았습니다. 나는 reduce()훨씬 더 빠른지 에 관심이 있었기 때문에, reduce()agf와 같은 방식으로 그 이외의 모든 것을 거의 수행했다. 가독성을 위해와 같은 is_even(n)표현식이 아닌 함수 호출을 보는 것이 좋습니다 n % 2 == 0.
steveha

9

다음은 더 파이썬적인 스타일로 동일한 알고리즘을 구현하는 @agf 솔루션의 대안입니다.

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)
    )

이 솔루션은 가져 오기없이 Python 2와 Python 3 모두에서 작동하며 훨씬 더 읽기 쉽습니다. 나는이 접근법의 성능을 테스트하지는 않았지만 무의식적으로 동일해야하며 성능이 심각한 문제라면 솔루션이 최적이 아닙니다.


7

SymPy에는 factorint 라는 업계 강력한 알고리즘이 있습니다 .

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

이 작업은 1 분 정도 걸렸습니다. 여러 가지 방법으로 전환됩니다. 위에 링크 된 설명서를 참조하십시오.

모든 주요 요소가 주어지면 다른 모든 요소를 ​​쉽게 만들 수 있습니다.


허용 된 답변이 위의 숫자를 고려하기에 충분한 시간 (즉, 영원)으로 실행되도록 허용 된 경우에도 다음 예와 같이 일부 큰 숫자에서는 실패합니다. 이것은 부주의 때문 int(n**0.5)입니다. 예를 들어, 때 n = 10000000000000079**2, 우리는이

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

이후 10000000000000079가 소수이고 , 허용 대답의 알고리즘은이 요소를 찾을 수 없을 것입니다. 그것은 단지 하나 하나가 아니라는 점에 유의하십시오. 더 큰 숫자의 경우 더 많이 해제됩니다. 이런 이유로 이런 종류의 알고리즘에서는 부동 소수점 숫자를 피하는 것이 좋습니다.


2
모든 제수를 찾을 수는 없지만 주요 요인 만 찾기 때문에 실제로 답이 아닙니다. 쉽게 말할 수있는 것이 아니라 다른 모든 요소를 ​​구축 할 수있는 방법을 보여 주어야합니다! 그건 그렇고, sympy.divisors 가이 질문에 대답하는 데 더 적합 할 수 있습니다.
Colin Pitrat

sympy.divisors는 허용되는 솔루션보다 훨씬 빠르지 않습니다.
Colin Pitrat 2016 년

@ ColinPitrat : sympy.divisors제수가 거의없는 숫자의 경우 훨씬 빠르지 않습니다. 벤치 마크가 있습니까?
Ry-

@Ry 나는 1 년 전에이 의견을 썼을 때 하나를했습니다. 작성하는 데 2 ​​분이 걸리므로 자유롭게 다시 확인하십시오.
Colin Pitrat

3
@ColinPitrat : 확인했습니다. 예상대로 허용되는 답변은 sympy.divisors100,000과 거의 같은 속도 이며 더 높은 속도 (실제로 중요한 경우)에는 느립니다. (물론, sympy.divisors같은 숫자 에서 작동합니다 10000000000000079**2.)
Ry-

7

n 최대 10 ** 16 (아마도 조금 더) 인 경우 여기에는 빠르고 순수한 Python 3.6 솔루션이 있습니다.

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 솔루션의 추가 개선. 다음 코드는 런타임 점근 적 복잡성을 변경하지 않고 모든 요소의 정렬 된 목록을 반환합니다.

    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

아이디어 : list.sort () 함수를 사용하여 nlog (n) 복잡성을 제공하는 정렬 된 목록을 얻는 대신; l2에서 list.reverse ()를 사용하면 O (n) 복잡성을 사용하는 것이 훨씬 빠릅니다. (파이썬을 만드는 방법입니다.) l2.reverse () 후에 l2를 l1에 추가하여 정렬 된 요소 목록을 얻을 수 있습니다.

l1에는 증가하는 i -s가 포함되어 있습니다 . l2 는 감소하는 q -s를 포함 합니다. 그것이 위의 아이디어를 사용하는 이유입니다.


확신 list.reverseO는 전체 복잡성을 변경하지 O (1),하지 않는 것이 (N)입니다.
agf

네 맞습니다. 제가 실수를. O (n)이어야합니다. (나는 지금 정답으로 답을 업데이트했습니다)
Pranjal Mittal

@ steveha 또는 @agf의 솔루션보다 약 2 배 느립니다.
jfs

l1 + l2.reversed()목록을 뒤집지 않고 돌아가서 작은 (2-3 %) 속도 향상을 얻을 수 있습니다 .
Rakurai

6

나는 효율성과 내 간단한 기능을 비교하기 위해 timeit 로이 훌륭한 답변을 대부분 시도했지만 여전히 여기에 나열된 것보다 성능이 뛰어납니다. 나는 그것을 공유하고 당신 모두가 어떻게 생각하는지 알 것이라고 생각했습니다.

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

작성된대로 테스트하려면 math를 가져와야하지만 math.sqrt (n)을 n **. 5로 바꾸면 잘 작동합니다. 중복이 세트에 존재할 수 없기 때문에 중복 검사에 시간을 낭비하지 않습니다.


좋은 물건! 당신은 (math.sqrt (N))의 + 1 개 외부 INT를 넣으면 다시 석회질이 루프의 각 반복 할 필요가 없습니다 때문에 당신이 그것에서 조금 더 성능을 얻을해야 for 루프
트리스탄 앞으로

3
@TristanForward : 파이썬에서 for 루프가 작동하는 방식은 아닙니다. xrange(1, int(math.sqrt(n)) + 1)한 번 평가됩니다.
Ry-

5

다음은 큰 숫자로 잘 수행되는 감소가없는 또 다른 대안입니다. sum목록을 병합하는 데 사용 됩니다.

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

1
이것은 불필요한 이차 시간이 아닙니다. 목록을 사용 sum하거나 reduce(list.__add__)평평하게 하지 마십시오 .
juanpa.arrivillaga

4

sqrt(number_to_factor)3 * 3 * 11 및를 가진 99와 같은 비정상적인 숫자 보다 큰 숫자를 가져와야합니다 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
숫자의 모든 요소를 ​​생성하지는 않습니다. 그것은을위한 숫자 등의 주요 요인 계산 x=8: 예상을 [1, 2, 4, 8], 가지고 :[2, 2, 2]
JFS

11은 @agf에 의해 주어진 코드에서 9가 컴퓨팅 될 때 발견됩니다. `i = 9-> 99 % 9 == 0-> 9 및 99 / 9 = 11이 추가됩니다.
Steinar Lima

4

숫자의 요인을 찾는 가장 간단한 방법 :

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

2

소수를 사용하여 훨씬 빠르게 진행하려는 경우의 예입니다. 이 목록은 인터넷에서 쉽게 찾을 수 있습니다. 코드에 주석을 추가했습니다.

# 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)]

Github에서 프로젝트를 만들었습니다 : github.com/Pierre-Thibault/Factor .
Pierre Thibault

2

이미 제시된 것보다 잠재적으로 더 효율적인 알고리즘입니다 (특히에 소수의 소수 팩터가있는 경우 n). 여기서 요점은 주요 요인을 찾을 때마다 시험 분할이 필요한 한계 까지 조정하는 것입니다 .

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

이것은 물론 여전히 시험 분할이며 더 멋진 것은 아닙니다. 따라서 여전히 효율성이 매우 제한적입니다 (특히 작은 제수가없는 큰 숫자의 경우).

이것은 python3입니다. //파이썬 2 (add from __future__ import division) 에 적응해야 할 유일한 부분 이어야합니다 .


1

를 사용 set(...)하면 코드가 약간 느려지 며 실제로 제곱근을 확인할 때만 필요합니다. 내 버전은 다음과 같습니다.

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:제곱근이 정수가 아니라 제곱근의 바닥 요인이다 조건은 (12), 같은 번호가 필요합니다.

이 버전은 숫자 자체를 반환하지 않지만 원하는 경우 쉽게 고칠 수 있습니다. 출력도 정렬되지 않습니다.

모든 숫자 1-200에서 10000 번 실행하고 모든 숫자 1-5000에서 100 번 실행되도록 시간을 정했습니다. Dansalmo, Jason Schorn 's, oxrock 's, agf 's, steveha 's, eryksun 's 솔루션을 포함하여 내가 테스트 한 다른 모든 버전보다 성능이 우수하지만 oxrock이 가장 가깝습니다.


1

최대 요소는 숫자보다 크지 않으므로

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

    return factors

voilá!


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

1과 우리가 찾으려고하는 숫자를 테스트 할 필요가 없다는 점을 지적하면서 다음 목록 이해와 같은 간단한 것을 사용하십시오.

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

제곱근의 사용을 참조하여, 우리는 (10)의 정수 부분의 요인을 찾아하고 싶은 말은 sqrt(10) = 4, 따라서 range(1, int(sqrt(10))) = [1, 2, 3, 4]4 명확하게 5를 벗어났습니다까지 테스트를.

내가 누락 된 것을 제안하지 않는 한,이 방법을 사용해야하는 경우을 사용하십시오 int(ceil(sqrt(x))). 물론 이것은 불필요한 함수 호출을 많이 발생시킵니다.


이 솔루션의 문제는 요인이 될 수없는 많은 숫자를 확인하는 것입니다. 작은 요인 쌍을 찾은 후 요인임을 이미 알고있을 때 각 요인 쌍의 높은 값을 개별적으로 확인합니다.
agf

1
@JasonSchorn : 2를 찾으면 10 / 2 = 5도 약수라는 것을 즉시 알 수 있습니다. 5를 별도로 확인할 필요가 없습니다! :)
Moberg

0

가독성과 속도를 고려하면 @oxrock의 솔루션이 최고이므로 python 3+ 용으로 작성된 코드는 다음과 같습니다.

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

이 질문을 보았을 때 numpy가 파이썬 루프보다 빠를 때 아무도 numpy를 사용하지 않았다는 사실에 놀랐습니다 . numpy로 @agf의 솔루션을 구현하면 평균 8 배 빠릅니다. . 나는 당신이 numpy로 다른 솔루션 중 일부를 구현하면 놀라운 시간을 얻을 수 있다고 믿습니다.

내 기능은 다음과 같습니다.

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 축의 숫자는 기능에 대한 입력이 아닙니다. 함수에 대한 입력은 2에서 x 축의 숫자에서 1을 뺀 값입니다. 따라서 10이 입력 인 경우 입력은 2 ** 10-1 = 1023입니다.

for 루프 대신 numpy를 사용한 성능 테스트 결과.


1
라이브러리를 사용하려는 경우 Evgeni Sergeev의 답변에서 볼 수 있듯이 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;
}

여기의 거의 모든 알고리즘은 숫자 * .5 범위로 제한되지만 실제로는 그 범위가 훨씬 작습니다. 실제로 숫자의 sqrt입니다. 우리가 더 낮은 제수를 가지고 있다면 우리는 더 쉽게 제곱을 얻을 수 있습니다. 그것은 단지 숫자 / 제수이기 때문에. 16의 경우 sqrt에 대해 4를 얻은 다음 1에서 4까지 반복합니다. 2는 16의 하한 제수이므로 16을 얻기 위해 16/2를 취합니다. 1이 있으면 16이 (16/1)이됩니다. 소인수 분해에 대해 배우면서 이것을 생각해 냈으므로 다른 곳에 게시되었는지는 알 수 없지만 많은 경우에도 작동합니다. 파이썬 솔루션을 제공 할 수 있습니다.
Tangang Atanga

-4

나는 이것이 가장 간단한 방법이라고 생각합니다.

    x = 23

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

올바른 결과를 제공하는 동안 귀하의 답변은 매우 비효율적입니다. 허용 된 답변을 살펴보십시오. 문제를 해결하는 방법에 대한 설명은 항상 답변이 더 유용하도록 돕습니다.
Nick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.