生成完美数字的最佳c ++程序

时间:2016-04-11 13:48:00

标签: c++ algorithm optimization perfect-numbers

我已经制作了以下程序来生成完美的数字,但在生成前4个数字(直到8128)后,我等了很长时间但没有发生任何事情。任何人都可以告诉我如何制作一个至少在long long int数据类型溢出之前生成完美数字的程序?

#include<iostream>
using namespace std;
void main() {
    unsigned long long int a = 4, sum = 0;
    while (true) {
        for (int i = 1; i <= (a/2); i++)
        {
            if (a%i == 0)
            {
                sum += i;
            }
        }
        if (sum == a) { cout << a<<" "; a += 2; sum = 0; }
        else { a += 2; sum = 0; }
    }
}

2 个答案:

答案 0 :(得分:2)

要知道一个数字是否完美,你需要总结所有除数,这意味着首先你必须找到它们。你正在使用一种非常缓慢的方法 - 基本上,所有可能的候选人的蛮力直到数字的一半。这将花费大量时间,并在一段时间后使其成为不可行的选择。如果你需要检查的数字是1'000'000,你的方法需要500'000分。分歧很慢。你必须改变方法。

您无需测试每个数字以确定它是否为除数。你可以这样做:对数字进行因子分解,使你有其主要因子,然后生成所有除数。

考虑到一个数字可能比野蛮地快 - 强迫所有可能的候选人直到一半。即使是一个简单的方法也可以轻松跳过所有偶数(当然除了2),你必须停在平方根,而不是半数。如果数字大约是1000'000,你只需要~500格,即奇数直到sqrt(1'000'000)。您可以轻松地进一步改进它(您可以找到很多关于如何优化搜索素因子的材料)。十年前我找到了一个名为“factor.exe”的程序,我现在无法提供可靠的下载(你可以查看thisthis,但我还没有验证了你可以在那里找到的东西,所以下载并自行承担风险!),这可能会在不到一秒的时间内计算出一个60位的数字,并且在几分钟内它可以计算大多数80位数。 here是一个网站,使用Javascript在大约0.01秒(平均)内将数字最多20个数字。这只是为了让您了解数字的分解速度有多快。

拥有素数因子后,方便地存储在向量中,您可以通过组合它们来生成所有除数。每个“组合”对应于为每个人选择是否接受。如果您有n个因子(不包括1),则可能有2个 n 因子。我知道,指数增长并不好,但大多数情况下你仍然使用有限的集合,因为n对于可以存储在long long中的数字而言 <cfsavecontent variable="returnStruct.Filecontent"> [{"date":"2016-04-05","stats":[{"type":"category","name":"5","metrics":{"blocks":1,"bounce_drops":0,"bounces":9,"clicks":4,"deferred":1,"delivered":1,"invalid_emails":8,"opens":4,"processed":1,"requests":1,"spam_report_drops":0,"spam_reports":1,"unique_clicks":3,"unique_opens":3,"unsubscribe_drops":0,"unsubscribes":9}}]}] </cfsavecontent> <cfset arr = DESerializeJSON(returnStruct.Filecontent) /> 不可能高于10(这只是经验虽然!)。重复的因素可以使事情变得更快(2 10 并不真正导致1024个不同的因素,实际上只有10个,因为你会发现它们中的每一个很多次),尽管实现这一点需要更多工作

因此,对于大约1'000'000的数字,您可以轻松地将其分解为最多500个分区,如果您有10个素因子,则可以有2个 10 = 1024个因子,每个这需要一些乘法(平均为5),最后你必须将它们相加。所以:500个分区,~5000个乘法,和~1000个和。这比您的方法所需的500'000分区要快得多。

最后,这种方法可能比你的方法快得多。

答案 1 :(得分:2)

您可以通过考虑小于sqrt(a)的因子,并推导出大于该值的匹配因子来提高因子分解的速度:

template<typename T>
T sum_factors(T n)
{
    T sum = 1;
    T i = 2;
    for (;  i * i < n;  ++i)
        sum += n%i ? 0 : i + n/i;
    if (i * i == n)
        sum += i;
    return sum;
}

我已将其作为一个函数提取出来,以便可以单独测试,并独立于搜索循环进行改进。

更好的是执行素数因子分解并对每个组合的乘积求和(忽略给出原始数字的'所有因素'组合,而不是忘记给出1的'无因素'组合。请记住,一旦超过候选人,你就可以停止计算这笔金额(我建议先订购总和以获得最大的条款,以获得最大利益)。

下一个明显的步骤是将工作分成更多核心:

#include <limits>
#include <iostream>

int main() {
    unsigned long long int a;
    const auto m = std::numeric_limits<decltype(a)>::max();

#pragma omp parallel for
    for (a = 1; a < m; ++a) {
        if (sum_factors(a) == a)
#pragma omp critical
            std::cout << a << std::endl;
    }
    return 0;
}

由于每个测试都是完全独立的,因此在给定时间内测试 n 次的次数,其中 n 是可用处理器的数量。 (使用gcc -fopenmp或等效文件进行编译。

但是,你真的想要使用Euclid–Euler generator甚至完美的数字,并且知道在1e1500以下没有奇数完美数字(远远超出任何C ++原始算术类型的范围)。< / p>