适当的除数算法存在问题

时间:2011-09-02 19:07:40

标签: c algorithm

我写了两个算法来得到给定数字的正确除数的总和,以找到完美的数字或数量。

long sum_divisors_1(int a)
{
    int i, t;
    long sum = 1;
    for (i = 2, t = sqrt(a); i < t + 1; i++) {
        if (a % i == 0) {
            sum += i;
            sum += a / i;
        }
    }
    if (a % t == 0)
    sum -= t;
    return sum;
}

long sum_divisors_2(int a)
{
    int i, sum;
    sum = 0;
    for (i = 1; i < (int) (a / 2 + 1); i++) {
        if (a % i == 0)
            sum += i;
    }
    return sum;
}

我认为它们都是正确的,第一个更快。但我只能从第二个算法得到正确的结果。代码的其他部分是相同的。

有什么建议吗?如何在实际工业规划中找到适当的除数?

提前致谢。

4 个答案:

答案 0 :(得分:2)

你的问题在于:

if (a % t == 0)
    sum -= t;

由于您将t从浮点转换为int,因此它将向下舍入为整数值。这也假设 t是实际的平方根。当数字具有因子x&amp;时,这将评估为真。 x+1(我发布的单元测试也在i = 6时失败,因为它的平方根是2.45而2是一个因子)。

检查确实应该是:

if (t*t == a)
    sum -= t;

答案 1 :(得分:1)

这是一个老问题,但我正在浏览。

有一种更快的算法可以找到合适的除数之和。

使用Sieve of Eratosthenes(或Atkin)找出数字的素因子。通过车轮分解,前1米素数可能需要30毫秒。

然后所有除数的总和是

For each n

    sum += (n ^ (m+1) - 1) / (n-1)

其中n是因子,m是该因子的幂。

例如220 2 ^ 2 5 11是因素

所以这是

的总和
2 ^ (2+1) - 1 / 1 *
5 ^ (1+1) - 1 / 4 *
11 ^ (1+1) - 1 / 10  
= 7 * 6 * 12
= 504

这是所有除数的总和,所以只需减去N

504-220 = 284

这比尝试所有数字要快得多,特别是如果你预先计算筛子并重复使用它。

答案 2 :(得分:0)

这是我用C#编写的一个简单的单元测试,它会很快使#1失效,因为#2是正确的:

for(int i = 4; i < 28124; i++)
{
    Assert.AreEqual(sum_divisors_2(i), sum_divisors_1(i), "Failed when i = {0}", i);
}

评论太大了......

答案 3 :(得分:0)

Templatetypedef解决了你的问题;然而,计算主要因子的最快方法是使用Eratostene筛子预先计算所有素数因子直至sqrt(MAX_INT),将其存储到数组中然后使用它来分解数字a。这真的非常快。