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