【问题标题】:Best way to find 'quite good' numbers up to 1 million?找到高达 100 万个“相当不错”的数字的最佳方法是什么?
【发布时间】:2021-10-06 12:22:29
【问题描述】:

我正在处理一项涉及“相当不错”的数字的作业。该任务将它们描述为:

“一个“相当好的”数字是一个整数,其“坏度”——除数之和与数字本身之差的大小——不大于指定值。例如,如果最大坏度为设置为 3,有 12 个小于 100 的“相当不错”的数字:2、3、4、6、8、10、16、18、20、28、32 和 64;你的任务是编写一个 C++ 程序,非常好,它确定小于指定值的指定最大坏度的数量。限制值和最大坏度在程序执行时指定为命令行参数。"

任务要求我编写一个程序,打印完美数字,指定的坏数限制高达一百万。所以,相当好的命令行参数 1000000 1 应该打印 2 4 6 8 16 28 32 64 128 256 496 512 1024 2048 4096 8128 8192 16384 32768 65536 131072 262144 524288.

我已经让它与以下代码一起工作

#include <iostream>

using namespace std;

int main(int argc, char *argv[]) {

    const int limit = argc > 1 ? atoi(argv[1]) : 1000000;
    const int badness = argc > 2 ? atoi(argv[2]) : 10;

    for(int number = 2; number < limit; number++) {
        int sum = 1;
        for (int factor = 2; factor < number; factor++){
            if (number % factor == 0) {
                sum += factor;
            }
        }

        if (number >= (sum - badness) && number <= (sum + badness)) {
            cout << number << " ";
        }
    }

    return 0;
}

唯一的问题是,这段代码在查找高达 100 万的“相当不错”的数字时速度太慢了。有什么办法可以优化吗?

谢谢

【问题讨论】:

  • 为什么值集中的所有素数都
  • @fabian 他们显然在谈论适当的除数,即不包括数字本身。
  • 一个数字“相当好”,类似于一个数字是“完美”的(如果 n 的除数之和不包括 n 等于 n,则 n 是完美的)。但是没有定义,从描述为工作的代码中可以清楚地看到(但太慢)。

标签: c++ algorithm c++11 math perfect-numbers


【解决方案1】:

如果 f 是 n 的因数,则 n/f 也是(尽管当 f 是 n 的平方根时,f 和 n/f 是相同的因数)。因此,您可以通过仅计算直到 sqrt(number) 的因子来使代码更快,然后当您找到一个时,还包括匹配的因子编号/因子(平方根情况除外)。

for (int factor = 2; factor * factor <= number; factor++){
    if (number % factor == 0) {
        sum += factor;
        if (factor * factor != number) {
            sum += number / factor;
        }
    }
}

limit为100万,badness为1的情况下,这段代码在我的机器上运行1.554s。等待原始代码完成几分钟后,我感到无聊。

为了使代码更快,您可以找到数字的素因数分解,并使用formula for the sum of the divisors based on the prime factorization

即使没有预先计算素数,使用这种方法在我的机器上也能运行 0.713 秒。这是我从number 计算sum 的代码:

int n = number;
int i = 2;
while (n > 1) {
    if (i * i > n) {
        sum *= (n + 1);
        break;
    }
    int pp = i;
    while (n % i == 0) {
        pp *= i;
        n /= i;
    }
    sum *= (pp - 1) / (i - 1);
    i += 1;
}
sum -= number;

它找到除number 的所有素幂,并且对于每个p^msum 乘以 (p^(m+1) - 1) / (p - 1)。与第一个解决方案一样,它提前停止,当 i*i &gt; n 时,这意味着 n 是一个素数。

在一般情况下,它比第一个解决方案快得多,因为尽管我们仍在进行试除法,但n 会随着素因数的找到而变小。

如果您已经预先计算了足够大的素数列表(也就是说,它至少包含一个大于极限平方根的素数),那么您在计算sum 时的效率可以再提高一点:

int n = number;
for (int i = 0; primes[i] * primes[i] <= n; ++i) {
    int pp = primes[i];
    while (n % primes[i] == 0) {
        pp *= primes[i];
        n /= primes[i];
    }
    sum *= (pp - 1) / (primes[i] - 1);
}
if (n > 1) sum *= (n + 1);
sum -= number;

以这种方式计算sum的代码在我的机器上运行时间为0.189s。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-03-13
    • 2016-05-31
    • 1970-01-01
    • 2010-09-23
    • 1970-01-01
    • 1970-01-01
    • 2013-11-11
    • 2020-09-19
    相关资源
    最近更新 更多