Чтобы решить проблему Проекта Эйлера № 5 , я написал следующую программу:
class p5
{
const int maxNumber = 20;
static void Main(string[] args)
{
Job(); // First warm-up call to avoid Jit latency
var sw = Stopwatch.StartNew();
var result = Job();
sw.Stop();
Debug.Assert(result == 232792560);
Console.WriteLine(result);
Console.WriteLine(sw.Elapsed);
Console.ReadLine();
}
private static int Job()
{
var result = Enumerable.Range(1, int.MaxValue - 1)
.Where(
n => Enumerable.Range(maxNumber / 2 + 1, maxNumber / 2).All(c => n % c == 0)
).First();
return result;
}
}
Однако я обнаружил, что это немного долго (17 секунд, врежим релиза), даже если он работает.
Есть ли какая-либо возможная оптимизация?
К вашему сведению, я пробовал с помощью метода AsParallel
, но, как и ожидалось, кусок работ слишком мал ипереключение контекста было тяжелее преимуществ (более 1 минуты):
var result = Enumerable.Range(1, int.MaxValue - 1).AsParallel()
.Where(
n => Enumerable.Range(maxNumber / 2 + 1, maxNumber / 2).All(c => n % c == 0)
).First();
return result;
[Редактировать] Согласно предложению Мартина, эта версия делится на 10 времени:
private static int Job()
{
var n =2;
bool result;
do
{
result = true;
for (int c = maxNumber / 2; c <= maxNumber; c++)
{
if (n % c > 0)
{
result = false;
break;
}
}
n ++;//= 2;
} while (!result);
return n;
}
[Edit] Подводя итог всем моим тестам, приблизительное время выполнения:
- Моя первая реализация: 20 секунд
- Удален внутренний вызов enumerable.Range (заменен напросто для цикла): 3 секунды
- Удалены внешние и внутренние перечислимые. Вызов диапазона: 1,5 секунды
- Только взятие четных чисел: (только с циклами, без перечисления. Диапазон): меньше 1second
- Использование евклидовых алгоритмов Gcd / LCm в соответствии с предложением drhirsch: 0,004 мс
Последнее предложение, безусловно, является хорошим ответом.Я благодарю drhirsch за то, что он предложил другой подход вместо простой оптимизации цикла