【问题标题】:How to find perfect numbers upto 10^18 in C?如何在C中找到高达10 ^ 18的完美数字?
【发布时间】:2017-06-20 16:41:09
【问题描述】:

我有一个 C 代码可以在下面找到大的完美数,

#include <stdio.h>

int main ()
{
    unsigned long long num,i,sum;

    while (scanf ("%llu",&num) != EOF && num)
    {
        sum = 1;

        for (i=2; i*i<=num; i++)
        {
            if (num % i == 0)
            {
                if (i*i == num)
                    sum += i;
                else
                    sum += (i + num/i);
            }
        }

        if (sum == num)
            printf ("Perfect\n");
        else if (sum > num)
            printf ("Abundant\n");
        else
            printf ("Deficient\n");
    }

    return 0;
}

我试图找出一个数字是完美的、丰富的还是不足的。我运行一个循环到num 的平方根以最小化运行时间。它工作正常&lt;= 10^15,但对于较大的值,执行时间太长。

例如,对于以下输入集,

8
6
18
1000000
1000000000000000
0

此代码显示以下输出,

Deficient
Perfect
Abundant
Abundant
Abundant

但是,对于 10^16,它并没有快速响应。

那么,有没有更好的方法来为过长的值找到一个完美的数字?或者有什么更好的算法可以在这里实现??? :)

【问题讨论】:

    标签: math number-theory perfect-numbers


    【解决方案1】:

    是的,有更好的算法。

    您的算法基本上是一个简单的算法——将一个数字的除数相加以找到...一个数字的除数之和(不包括它自己)。但是你可以使用数论公式来求一个数(包括它自己)的除数之和。如果除以n 的素数是p1p2、...、pk,并且这些素数在n 的规范分解中的幂是a1a2、... ,ak,则n的除数之和为

    (p1**(a1+1) - 1) / (p1 - 1) * (p2**(a2+1) - 1) / (p2 - 1) * ...
        * (pk**(ak+1) - 1) / (pk - 1)
    

    您可以比找到 所有 n 的除数更快地找到主要除数及其指数。从上面的表达式中减去n,你就得到了你想要的总和。

    当然,有一些技巧可以更有效地找到pis 和ais:我将把它留给你。


    顺便说一句,如果你的目的只是为了找到完美的数字,就像你的标题一样,你最好使用Euclid's formula for even prime numbers。通过检查所有2**p-1 中的素数p 来查找梅森素数,看看它们是否是素数——也有这样做的捷径——然后从那个梅森素数构造一个完美数。不过,这会遗漏任何odd perfect numbers。如果你找到了,请让数学界知道——这会让你举世闻名。

    当然,找到完美数字的最快方法是使用其中的一些 the lists already made

    【讨论】:

    • 这有帮助。 :) ...感谢分享您的知识:)
    【解决方案2】:

    这是一个数字分解的问题。你可以在这里阅读更多:https://en.wikipedia.org/wiki/Integer_factorization

    很遗憾,对您来说没有好消息 - 数字越大,花费的时间就越长。

    从您的代码开始,请尽量不要在每次迭代时乘以 i*i。 代替: for (i=2; i*i

    先计算num的平方根,再比较 i &lt;= square_root_of_num in the loop.

    【讨论】:

      【解决方案3】:
      // Program to determine whether perfect or not
      
      # include <bits/stdc++.h>
      using namespace std;
      
      map<long long int, int> mp;    // to store prime factors and there frequency
      
      void primeFactors(long long int n)
      {
      // counting the number of 2s that divide n
      while (n%2 == 0)
      {
          mp[2] = mp[2]+1;
          n = n/2;
      }
      
      long long int root = sqrt(n);
      // n must be odd at this point.  So we can skip every even numbers next
      for (long long int i = 3; i <= root; i = i+2)
      {
          // While i divides n, count frequency of i prime factor and divide n
          while (n%i == 0)
          {
              mp[i] = mp[i]+1;
              n = n/i;
          }
      }
      
      // This condition is to handle the case whien n is a prime number
          // greater than 2
          if (n > 2)
          {
              mp[n] = mp[n]+1;
          }
      }
      
      long long int pow(long long int base, long long int exp)
      {
          long long int result = 1;
          base = base;
          while (exp>0)
          {
              if (exp & 1)
                  result = (result*base);
              exp >>= 1;
              base = (base*base);
          }
          return result;
      }
      
      int main ()
      {
          long long num, p, a, sum;
      
          while (scanf ("%lld",&num) != EOF && num)
          {
              primeFactors(num);
              sum = 1;
      
              map<long long int, int> :: iterator i;
              for(i=mp.begin(); i!=mp.end(); i++)
              {
                  p = i->first;
                  a = i->second;
                  sum = sum*((pow(p,a+1)-1)/(p-1));
              }
      
              if (sum == 2*num)
                  printf ("Perfect\n");
              else if (sum > num)
                  printf ("Abundant\n");
              else
                  printf ("Deficient\n");
      
              mp.clear();
          }
      
          return 0;
      }
      

      【讨论】:

      • 我用完美的数字 2305843008139952128 尝试了这段代码,但它给出了错误的答案,尽管数字在 long long int 的范围内。问题似乎是这个表达式sum = (sum*(pow(p,a+1)-1))/(p-1); 在表达sum = sum * ((pow(p,a+1)-1) / (p-1)); 时可以正常工作,即乘法和除法的顺序很重要。另一种修复(或升级)是在整个过程中使用unsigned long long int
      猜你喜欢
      • 2020-02-27
      • 1970-01-01
      • 2020-01-24
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多