5

作为编程挑战的一部分,我用 C# 编写了一个程序来查找一定范围内的完美数字。但是,我意识到计算超过 10000 的完美数字时非常慢。是否有任何优化方法可以找到完美数字?我的代码如下:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleTest
{
 class Program
 {
  public static List<int> FindDivisors(int inputNo)
  {
   List<int> Divisors = new List<int>();
   for (int i = 1; i<inputNo; i++)
   {
    if (inputNo%i==0)
     Divisors.Add(i);
   }
   return Divisors;
  }

  public static void Main(string[] args)
  { 
   const int limit = 100000;

   List<int> PerfectNumbers = new List<int>();
   List<int> Divisors=new List<int>();
   for (int i=1; i<limit; i++)
   {
    Divisors = FindDivisors(i);
    if (i==Divisors.Sum())
     PerfectNumbers.Add(i);
   }

   Console.Write("Output =");

   for (int i=0; i<PerfectNumbers.Count; i++)
   {
    Console.Write(" {0} ",PerfectNumbers[i]);
   }

   Console.Write("\n\n\nPress any key to continue . . . ");
   Console.ReadKey(true);
  }
 }
} 
4

7 回答 7

4

使用公式

测试完美 = 2 n-1 (2 n - 1)

要产生可能性,然后检查该数字是否实际上是完美的。

试试这个睡前阅读

于 2010-04-16T08:38:07.213 回答
2

完美数会改变吗?不,看这里。当然,它们应该计算一次然后存储。在您的情况下,唯一的结果将是

6
28
496
8128

下一个是 33550336。超出您的范围。

于 2010-04-16T08:32:58.643 回答
1

只是我很明显的一个:你不需要检查每个除数。过去找除数没有意义inputNo/2。这减少了一半的计算,但这并不是快一个数量级。

于 2010-04-16T09:52:45.767 回答
0

解决此类问题的一种方法是在每个数字的内存中构建一个巨大的数组,然后将数字交叉。

于 2010-04-16T08:35:12.313 回答
0

如果您仍在寻找计算完美数字的东西。这通过前一万很快,但三千三百万的数字有点慢。

public class Perfect {
private static Perfect INSTANCE = new Perfect();

public static Perfect getInstance() {
    return INSTANCE;
}

/**
 * the method that determines if a number is perfect;
 * 
 * @param n
 * @return
 */
public boolean isPerfect(long n) {
    long i = 0;
    long value = 0;
    while(++i<n){
        value = (0 == n%i?value+i:value);
    }
    return n==value;
}
}
于 2012-01-18T21:55:08.090 回答
0

对于任何对基于 LINQ 的方法感兴趣的人,在确定调用者提供的整数值是否为完美数字时,以下方法对我来说非常有效且有效。

bool IsPerfectNumber(int value)
{
    var isPerfect = false;

    int maxCheck = Convert.ToInt32(Math.Sqrt(value));
    int[] possibleDivisors = Enumerable.Range(1, maxCheck).ToArray();
    int[] properDivisors = possibleDivisors.Where(d => (value % d == 0)).Select(d => d).ToArray();
    int divisorsSum = properDivisors.Sum();

    if (IsPrime(divisorsSum))
    {
        int lastDivisor = properDivisors.Last();
        isPerfect = (value == (lastDivisor * divisorsSum));
    }

    return isPerfect;
}

为了简单明了,我在 IsPerfectNumber() 中使用的 IsPrime() 实现被省略。

于 2017-05-28T05:36:43.250 回答
0

要继续查尔斯·加金特的回答,有一种非常快速的方法可以检查梅森数 aka 2^n - 1 是否为素数。它被称为Lucas-Lehmer 测试 基本的伪代码(取自维基百科页面)是:

// Determine if Mp = 2p − 1 is prime for p > 2
Lucas–Lehmer(p)
    var s = 4
    var M = 2p − 1
    repeat p − 2 times:
        s = ((s × s) − 2) mod M
    if s == 0 return PRIME else return COMPOSITE
于 2017-12-05T20:27:58.777 回答