EDIT_ADD: Если Уилл Несс прав, цель вопроса состоит в том, чтобы просто выводить непрерывный поток простых чисел до тех пор, пока программа работает (нажатие Pause / Break для паузы и любой клавиши для повторного запуска) с нет серьезных надежд на достижение этого верхнего предела, тогда код должен быть написан без аргумента верхнего предела и проверки диапазона на «истина» для первого цикла for. С другой стороны, если в вопросе нужно было напечатать простые числа до предела, то следующий код будет выполнять работу намного более эффективно, используя пробное деление только для нечетных чисел, с тем преимуществом, что он вообще не использует память (его также можно преобразовать в непрерывный цикл, как указано выше):
static void primesttt(ulong top_number) {
Console.WriteLine("Prime: 2");
for (var i = 3UL; i <= top_number; i += 2) {
var isPrime = true;
for (uint j = 3u, lim = (uint)Math.Sqrt((double)i); j <= lim; j += 2) {
if (i % j == 0) {
isPrime = false;
break;
}
}
if (isPrime) Console.WriteLine("Prime: {0} ", i);
}
}
Во-первых, код вопроса не выводит данные, потому что его переменные цикла являются целыми числами, а протестированный предел - огромным длинным целым числом, что означает, что цикл не может достичь предела, создавая внутренний цикл EDITED: strong > посредством чего переменная 'j' возвращается к отрицательным числам; когда переменная 'j' возвращается к -1, проверяемое число не проходит проверку на простоту, потому что все числа делятся на -1 END_EDIT без остатка. Даже если бы это было исправлено, код вопроса выдает очень медленный вывод, потому что он связан с 64-битным делением очень большого количества составных чисел (все четные числа плюс нечетные составные числа) на весь диапазон чисел до этой вершины. число десять в шестнадцатой степени для каждого возможного простого числа. Приведенный выше код работает, потому что он ограничивает вычисления только нечетными числами и делает только деления по модулю вплоть до квадратного корня из текущего проверяемого числа.
Для отображения простых чисел до миллиарда требуется час или около того, поэтому можно представить, сколько времени потребуется, чтобы отобразить все простые числа до десяти тысяч триллионов (10 в шестнадцатой степени), тем более, что вычисления становятся медленнее. с увеличением дальности. END_EDIT_ADD
Хотя однострочный (своего рода) ответ от @SLaks с использованием Linq работает, на самом деле это не Решето Эратосфена, поскольку это просто неоптимизированная версия Trial Division, неоптимизированный тем, что не исключает нечетные простые числа, не начинается с квадрата найденного базового простого числа и не прекращает отбраковку для базовых простых чисел большего размера чем квадратный корень из верхнего числа, чтобы просеять. Это также довольно медленно из-за множественных вложенных операций перечисления.
На самом деле это злоупотребление методом Linq Aggregate и неэффективное использование первого из двух сгенерированных Linq Range. Он может стать оптимизированным пробным отделом с меньшими накладными расходами на перечисление следующим образом:
static IEnumerable<int> primes(uint top_number) {
var cullbf = Enumerable.Range(2, (int)top_number).ToList();
for (int i = 0; i < cullbf.Count; i++) {
var bp = cullbf[i]; var sqr = bp * bp; if (sqr > top_number) break;
cullbf.RemoveAll(c => c >= sqr && c % bp == 0);
} return cullbf; }
который работает во много раз быстрее, чем ответ SLaks. Однако он по-прежнему медленный и требует больших затрат памяти из-за генерации списка и множественных перечислений, а также множественных операций деления (подразумеваемых по модулю).
Следующая настоящая реализация Решета Эратосфена работает примерно в 30 раз быстрее и требует гораздо меньше памяти, поскольку она использует только однобитовое представление на просеянное число и ограничивает его перечисление конечным выходом последовательности итератора, а также оптимизирует обработку только нечетных композитов. и только отбраковка от квадратов базовых простых чисел для базовых простых чисел до квадратного корня из максимального числа, как показано ниже:
static IEnumerable<uint> primes(uint top_number) {
if (top_number < 2u) yield break;
yield return 2u; if (top_number < 3u) yield break;
var BFLMT = (top_number - 3u) / 2u;
var SQRTLMT = ((uint)(Math.Sqrt((double)top_number)) - 3u) / 2u;
var buf = new BitArray((int)BFLMT + 1,true);
for (var i = 0u; i <= BFLMT; ++i) if (buf[(int)i]) {
var p = 3u + i + i; if (i <= SQRTLMT) {
for (var j = (p * p - 3u) / 2u; j <= BFLMT; j += p)
buf[(int)j] = false; } yield return p; } }
Приведенный выше код вычисляет диапазон всех простых чисел до десяти миллионов примерно за 77 миллисекунд на Intel i7-2700K (3,5 ГГц).
Любой из двух статических методов может быть вызван и протестирован с помощью операторов using и статического метода Main следующим образом:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
static void Main(string[] args) {
Console.WriteLine("This program generates prime sequences.\r\n");
var n = 10000000u;
var elpsd = -DateTime.Now.Ticks;
var count = 0; var lastp = 0u;
foreach (var p in primes(n)) { if (p > n) break; ++count; lastp = (uint)p; }
elpsd += DateTime.Now.Ticks;
Console.WriteLine(
"{0} primes found <= {1}; the last one is {2} in {3} milliseconds.",
count, n, lastp,elpsd / 10000);
Console.Write("\r\nPress any key to exit:");
Console.ReadKey(true);
Console.WriteLine();
}
который покажет количество простых чисел в последовательности до предела, последнее найденное простое число и время, затраченное на их перечисление.
EDIT_ADD: однако, чтобы произвести перечисление числа простых чисел меньше десяти тысяч триллионов (десять в шестнадцатой степени), как задается вопрос, требуется сегментированный постраничный подход с использованием многоядерной обработки. но даже с C ++ и очень оптимизированным PrimeSieve для этого потребуется около 400 часов, чтобы просто произвести количество найденных простых чисел, и в десятки раз больше, чтобы перечислить их все, чтобы в течение года сделать то, что задает вопрос. Чтобы сделать это с использованием неоптимизированного алгоритма пробного деления, потребуются суперэоны и очень-очень много времени даже при использовании оптимизированного алгоритма пробного деления, например, от десяти до двух миллионов лет (это два миллиона нулевых лет !! !).
Неудивительно, что его настольный компьютер просто остановился, когда он попробовал !!!! Если бы он попробовал меньший диапазон, такой как один миллион, он все равно обнаружил бы, что это занимает диапазон секунд, как это было реализовано.
Решения, которые я публикую здесь, тоже не помогут, так как даже последнее Сито Эратосфена потребует около 640 Терабайт памяти для этого диапазона.
Вот почему только сегментированный по страницам подход, такой как PrimeSieve, может справиться с подобными проблемами для указанного диапазона, и даже это требует очень много времени, от нескольких недель до нескольких лет, если у вас нет доступа к суперкомпьютеру с сотни тысяч ядер. END_EDIT_ADD
person
GordonBGood
schedule
06.12.2013