如何优化算法的速度/效率?
我需要计算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秒的超时。
答案 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的核心数或者它可以提供多少并行度。
我希望这能解决你的问题。