Finding perfect numbers (optimization)

2019-06-22 05:26发布

I coded up a program in C# to find perfect numbers within a certain range as part of a programming challenge . However, I realized it is very slow when calculating perfect numbers upwards of 10000. Are there any methods of optimization that exist for finding perfect numbers? My code is as follows:

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);
  }
 }
} 

7条回答
来,给爷笑一个
2楼-- · 2019-06-22 05:38

Just the obvious one from me: you don't need to check every divisor. No point looking for divisors past inputNo/2. That cuts down half of the calculations, but this is not an order of magnitude faster.

查看更多
该账号已被封号
3楼-- · 2019-06-22 05:38

One way to solve things like this involves building a huge array in memory of every number, and then crossing numbers out.

查看更多
兄弟一词,经得起流年.
4楼-- · 2019-06-22 05:41

Do perfect numbers change? No. Look here. Surely, they should be calculated once and then stored. In your case, the only results will be

6
28
496
8128

The next one is 33550336. Outside your range.

查看更多
▲ chillily
5楼-- · 2019-06-22 05:42

For anyone interested in a LINQ based approach, the following method worked quite well and efficiently for me in determining whether or not a caller supplied integer value is a perfect number.

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;
}

For simplicity and clarity, my implementation for IsPrime(), which is used within IsPerfectNumber(), is omitted.

查看更多
你好瞎i
6楼-- · 2019-06-22 05:46

Use the formula

testPerfect = 2n-1(2n - 1)

to generate possiblities then check wether the number is in fact perfect.

try this for some bedtime reading

查看更多
等我变得足够好
7楼-- · 2019-06-22 05:46

To continue from Charles Gargent's answer there is a very quick way to check if a Mersenne Number a.k.a. 2^n - 1 is prime. It is called the Lucas-Lehmer test The basic pseudocode though (taken from the Wikipedia page) is:

// 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
查看更多
登录 后发表回答