数字的除数的数量不小于另一个数字的除数

时间:2012-10-30 18:42:19

标签: performance algorithm math prime-factoring

是否有任何有效的方法可以找到一个数字(例如n)的除数,这些除数不小于另一个数(比如m)。 n最高可达10 ^ 12。 我想过筛选算法&然后找出除数的数量。 我的方法检查从m到n的平方根的所有数字。 但我认为还有另一种方式(有效)来做到这一点。

3 个答案:

答案 0 :(得分:3)

如果你知道主要因素,很容易找到数字的除数;只需考虑所有因素的多重性的所有可能组合。

对于小于10 ^ 12的 n ,试验分割应该是一种足够快的因子分解方法,因为您只需检查最多10 ^ 6的潜在因子。

编辑:添加关于“所有可能的组合”的讨论和通过试验分工的因子分析。

考虑数字24505 = 5 * 13 * 13 * 29.要枚举其除数,请采用所有因子的多重性的所有可能组合:

5^0 * 13^0 * 29^0 = 1
5^0 * 13^0 * 29^1 = 29
5^0 * 13^1 * 29^0 = 13
5^0 * 13^1 * 29^1 = 377
5^0 * 13^2 * 29^0 = 169
5^0 * 13^2 * 29^1 = 4901
5^1 * 13^0 * 29^0 = 5
5^1 * 13^0 * 29^1 = 145
5^1 * 13^1 * 29^0 = 65
5^1 * 13^1 * 29^1 = 1885
5^1 * 13^2 * 29^0 = 845
5^1 * 13^2 * 29^1 = 24505

通过试验部门计算一个数字并不难。这是算法,您可以将其翻译成您喜欢的语言;它足够快,数量高达10 ^ 12:

function factors(n)
    f = 2
    while f * f <= n
        if n % f == 0
            output f
            n = n / f
        else
            f = f + 1
    output n

让我们看一下24505的分解。最初 f 是2,但是24505%2 = 1,所以 f 增加到3.然后 f < / em> = 3且 f = 4也无法除 n ,但24505%5 = 0,因此5是因子24505且 n 减少到24505/5 = 4901.现在 f = 5没有变化,但它没有划分 n ,同样是6,7,8,9,10, 11和12,但最后4901%13 = 0,所以13是因子4901(也是24505), n 减少到4901/13 = 377.此时 f = 13未更改,13再次成为除数,此时减少的 n = 377,因此输出另一个因子13并且 n 减少此时13 * 13 = 169大于29,因此while循环退出,最终因子29输出;这是有效的,因为如果 n = pq ,那么 p q 中的一个必须小于 n 的平方根>(除非 p q 相等且 n 是完美的正方形),并且因为我们已经通过所有 p q 小于29的平方根,它必须是素数,因而是最终因子。所以我们看到24505 = 5 * 13 * 13 * 29.

我在essay 使用素数编程中讨论了这些算法。

答案 1 :(得分:2)

以下是一个示例程序,用于计算大于m的n的除数。如果有c个除数,则largeDivs()代码在时间O(c)中运行。 largeDivs()也以n的表示作为因式数开始,其中nset是形式对(p_i,k_i)的列表,使得n = Product {p_i ** k_i for i in 1..h}。程序后显示一些示例输出。 check()例程用于演示largeDivs()产生正确的结果。 check()需要很长时间才能得到较小的m值。

def largeDivs(n, nset, m):
    p, k = nset[-1]
    dd = 0
    if len(nset) > 1:
        nn, mm = n / p**k, m
        for i in range(k+1):
            dd += largeDivs(nn, nset[:-1], mm)
            mm = (mm + p-1)/p
    else:
        c, v = k+1, 1
        while v<m and c>0:
            c, v = c-1, v*p
        return c
    return dd

def check (n,m,s):
    if m<1:
        return s
    c = 0
    for i in range(m,n+1):
        if (n%i)==0:
            c += 1
    return c


tset = [(2,3),(3,2),(11,1),(17,1),(23,2)]
n = s = 1
for i in tset:
    s *= 1+i[1]
    n *= i[0]**i[1]
print 'n=',n, '  s=',s
m=0
for i in range(8):
    print 'm:', m, '\t', largeDivs(n, tset, m), '  Check:',check(n,m,s)
    m = 10*m + 5

示例输出:

n= 7122456   s= 144
m: 0    144   Check: 144
m: 5    140   Check: 140
m: 55   124   Check: 124
m: 555  95   Check: 95
m: 5555     61   Check: 61
m: 55555    28   Check: 28
m: 555555   9   Check: 9
m: 5555555  1   Check: 1

答案 2 :(得分:0)

这取决于应用程序,但如果性能是这样的问题,我会使用预先生成的哈希表。显然,10 ^ 12个条目在内存中存储可能是不切实际的(或者至少是不合需要的),因此我会对 k th 素数进行除法测试,生成散列表条目仅适用于不能被第一个 k 素数整除的数字。

例如,虽然粗略地编写和未经测试,但这应该给你一个想法:

int   number   = 23456789;
int   primes[] = {2, 3, 5, 7, 11, 13, 17, 19, 0};
int   pfactors = 0;
int*  prime = primes;
float temp;

// check until we reach the end of the array (0)
while (prime)
{
    // divide by prime and check if result is integer
    temp = (float)number/*prime;
    if (temp == floor(temp))
    {
        // if so, increment count of prime factors and loop (same prime again!)
        pfactors++;
        number = (int)temp;
    }
    else
    {
        // else try the next prime
        prime++;
    }
}

// finally, rely on hash table magic
pfactors += pregenerated_hash[number];