素数最多为10 ^ 15

时间:2017-02-23 14:17:14

标签: c# algorithm math

如何优化算法的速度/效率?

我需要计算1至10 ^ 15范围内的素数总数 编辑:约束:last-first<=10^9
以下代码适用于较小的范围(从1到2000000),需要4秒(差不多)。

static void Main(string[] args)
    {
        string[] s = Console.ReadLine().Split(' ');
        DateTime start = DateTime.Now;
        var first = Convert.ToInt64(s[0]);
        var last = Convert.ToInt64(s[1]);
        int counter = 0;
        for (long i = first; i <= last; i++)
        {
            if (i > 2 && i%2==0)
            {
                continue;
            }
            if (isPrime(i))
            {
                counter++;
            }
        }
        Console.WriteLine(counter);
        TimeSpan duration = DateTime.Now - start;
        Console.WriteLine(duration.TotalMilliseconds);
        Console.ReadLine();
    }
    public static bool isPrime(long number)
    {
        if (number == 1) return false;
        if (number == 2) return true;

        for (int i = 2; i <= Math.Ceiling(Math.Sqrt(number)); ++i)
        {
            if (number % i == 0) return false;
        }
        return true;
    }

正如您在for loop中所看到的,首先我会检查该数字是否为i > 2 && i%2==0,因为在这种情况下,该数字不是素数。

是否有更多技巧可以避免这些数字无法进入isPrime方法,或者避免超时的最佳解决方案是什么?注意:此代码有效,但问题是我需要避免4秒的超时。

1 个答案:

答案 0 :(得分:-2)

我解决这个问题的方法是,我在SlicerMain函数中将最大数量切成5个切片。 SlicerMain函数进一步获取每个切片的下限和上限,并将其发送到PrimeCounter函数,该函数返回切片边缘之间的素数总数。

static void Main(string[] args)
    {
       DateTime start = DateTime.Now;

       var max = 2000000;// Math.Pow(10, 15);
       int slices = 5;
       SlicerMain(slices, max);

       Console.WriteLine(counter);
       TimeSpan duration = DateTime.Now - start;
       Console.WriteLine(duration.TotalMilliseconds);

       Console.ReadLine();
   }

/// <summary>
/// It slices the big number into smaller ones
/// </summary>
/// <param name="slices">Total Number of slices</param>
/// <param name="max">Big number</param>
public static void SlicerMain(int slices, double max)
    {
       Parallel.For(0, slices,
                    index =>
                         {
                             double up = max * (index + 1) / slices;
                             double low = max * (index) / slices + 1;
                             Interlocked.Add(ref counter, PrimCounter(low, up));
                         });
    }

/// <summary>
/// Optimized Prime Counter
/// </summary>
/// <param name="first">slice lower bound</param>
/// <param name="last">slice uper bound</param>
/// <returns>Count of prime numbers</returns>
public static int PrimCounter(double first, double last)
        {
            int localCounter = 0;
            for (double a = first; a < last; a++)
            {
                bool prime = true;
                for (int c = 2; c * c <= a; c++)
                {
                    if (a % c == 0)
                    {
                        prime = false;
                        break;
                    }
                }
                if (prime)
                    localCounter++;
            }
            return localCounter;
        }

slicing用于并行和利用计算机的最大资源。提高切片数量会减少计算质数的总时间,但您可以将其提升到PC的核心数或者它可以提供多少并行度。 我希望这能解决你的问题。