如何找到多个素因子以获得除数

时间:2014-07-03 04:18:01

标签: python-2.7 prime-factoring

你可能已经猜到我正在通过标题做项目euler#12。我的暴力解决方案耗时太长,所以我一直在寻找可以理解的优化

我有兴趣扩展概述here

的策略

我尝试解决这个问题的方法是使用Eratosthenes的Sieve来获得这样的主要因素:

divs = []

multiples = set()
for i in xrange(2, n + 1):
    if i not in multiples:
        if n % i == 0:
            divs.append(i)
        multiples.update(xrange(2*i, n+1, i))
return divs

这本身就是一个问题,因为第8行在程序进入答案范围之前很久就会产生溢出错误(76576500)。

现在,假设我能够得到主要因素,我怎样才能有效地找到它们各自的多重性?

4 个答案:

答案 0 :(得分:1)

借用其他答案:

数字a1 ^ k1 * a2 ^ k2 * ... an ^ kn的因子数=(k1 + 1)*(k2 + 1)......(kn + 1)

您可以使用以下代码获取低于特定数字的素数: 由Fastest way to list all primes below N

提供
n = number

def primesfrom2to(n):
    """ Input n>=6, Returns a array of primes, 2 <= p < n """
    sieve = numpy.ones(n/3 + (n%6==2), dtype=numpy.bool)
    for i in xrange(1,int(n**0.5)/3+1):
        if sieve[i]:
            k=3*i+1|1
            sieve[       k*k/3     ::2*k] = False
            sieve[k*(k-2*(i&1)+4)/3::2*k] = False
    return numpy.r_[2,3,((3*numpy.nonzero(sieve)[0][1:]+1)|1)]

primes = primesfrom2to(n).tolist()  # list of primes.
primes = map(int, primes)
factors = {}
for prime in primes:
    n = number
    factor = 0
    while True:
        if n%prime == 0:
            factor += 1
            n /= prime
            factors[prime] = factor
        else: break

因素将为您提供多种主要因素。

答案 1 :(得分:1)

我的标准素数脚本附在下面;它提供了Eratsothenes的Sieve来生成质数,一个Miller-Rabin素性检验,一个使用2,3,5轮和Pollard的rho方法计算整数的函数,数值理论函数sigma计算x'的总和一个整数除数的幂,使用你在帖子中引用的方法,以及一个从给定整数开始计算等分序列的函数。鉴于该脚本,很容易解决Project Euler 12,记住x = 0的sigma返回整数除数的计数:

$ python
Python 2.6.8 (unknown, Jun  9 2012, 11:30:32)
[GCC 4.5.3] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> execfile('primes.py')
>>> factors(76576500)
[2, 2, 3, 3, 5, 5, 5, 7, 11, 13, 17]
>>> sigma(0,76576500)
576
>>> i, t = 1, 1
>>> while sigma(0, t) < 500:
...     i += 1; t += i
...
>>> print t
76576500

您可以在 http://programmingpraxis.codepad.org/V5LiI8V9运行该程序,您会在my blog找到很多素数。这是代码:

# prime numbers

def primes(n): # sieve of eratosthenes
    i, p, ps, m = 0, 3, [2], n // 2
    sieve = [True] * m
    while p <= n:
        if sieve[i]:
            ps.append(p)
            for j in range((p*p-3)/2, m, p):
                sieve[j] = False
        i, p = i+1, p+2
    return ps

# from random import randint

seed = 17500728 # RIP j s bach

def random(): # float on range [0,1)
    global seed
    seed = (69069 * seed + 1234567) % 4294967296
    return seed / 4294967296.0

def randint(lo,hi): # int on range [lo,hi)
    return int((hi - lo) * random()) + lo

def isPrime(n, k=5): # miller-rabin
    if n < 2: return False
    for p in [2,3,5,7,11,13,17,19,23,29]:
        if n % p == 0: return n == p
    s, d = 0, n-1
    while d % 2 == 0:
        s, d = s+1, d/2
    for i in range(k):
        x = pow(randint(2, n-1), d, n)
        if x == 1 or x == n-1: continue
        for r in range(1, s):
            x = (x * x) % n
            if x == 1: return False
            if x == n-1: break
        else: return False
    return True

# from fractions import gcd

def gcd(a,b): # greatest common divisor
    if b == 0: return a
    return gcd(b, a % b)

def insertSorted(x, xs): # insert x in order
    i, ln = 0, len(xs)
    while i < ln and xs[i] < x: i += 1
    xs.insert(i,x)
    return xs

def factors(n, b2=-1, b1=10000): # 2,3,5-wheel, then rho
    if -1 <= n <= 1: return [n]
    if n < -1: return [-1] + factors(-n)
    wheel = [1,2,2,4,2,4,2,4,6,2,6]
    w, f, fs = 0, 2, []
    while f*f <= n and f < b1:
        while n % f == 0:
            fs.append(f)
            n /= f
        f, w = f + wheel[w], w+1
        if w == 11: w = 3
    if n == 1: return fs
    h, t, g, c = 1, 1, 1, 1
    while not isPrime(n):
        while b2 <> 0 and g == 1:
            h = (h*h+c)%n # the hare runs
            h = (h*h+c)%n # twice as fast
            t = (t*t+c)%n # as the tortoise
            g = gcd(t-h, n); b2 -= 1
        if b2 == 0: return fs
        if isPrime(g):
            while n % g == 0:
                fs = insertSorted(g, fs)
                n /= g
        h, t, g, c = 1, 1, 1, c+1
    return insertSorted(n, fs)

def sigma(x, n, fs=[]): # sum of x'th powers of divisors of n
    def add(s, p, m):
        if x == 0: return s * (m+1)
        return s * (p**(x*(m+1))-1) / (p**x-1)
    if fs == []: fs = factors(n)
    prev, mult, sum = fs.pop(0), 1, 1
    while len(fs) > 0:
        fact = fs.pop(0)
        if fact <> prev:
            sum, prev, mult = add(sum, prev, mult), fact, 1
        else: mult += 1
    return add(sum, prev, mult)

def aliquot(n): # print aliquot sequence
    s, ss, k, fs = n, [n], 0, factors(n)
    print n, k, s, fs
    while s > 1:
        s, k = sigma(1,s,fs) - s, k + 1
        fs = factors(s)
        print n, k, s, fs
        if s in ss: return "cycle"
        ss.append(s)
    return ss.pop(-2)

答案 2 :(得分:1)

即使您将自己局限于相对简单的算法(即不是布伦特算法或任何更高级的算法),您的分解方法也远非最优化。

每次找到素数因子时,除以该因子直到它不再可被整除。你能做到的次数就是多样性。

除法后继续使用商,而不是原始数字。

找出因子并除以直到剩余商小于你的除数的平方。在这种情况下,商是1或素数(具有多重性1的最后一个素数因子)。

要找到因子,从2开始进行试验除法,从3开始进行奇数。任何非素数都不会成为问题,因为它的素因子在到达之前就已经被删除了。

使用正确的数据结构来表示素数因子及其多样性(地图或多重集)。

您也可以直接计算除数的数量,而不存储分解。每当您找到素数因子及其多重性时,您可以通过乘以除数的公式中的相应因子来累积结果。

如果你需要对不太大的数字进行多次分解,你可以为每个数组索引预先计算一个具有最小除数的数组,并使用它来快速找到除数。

答案 3 :(得分:0)

示例:28 = 2 ^ 2 * 7 ^ 1 因子数=(2 + 1)*(1 + 1)= 6

通常a ^ k1 * a ^ k2 .. a ^ kn 因子数=(k1 + 1)*(k2 + 1)......(kn + 1)