tabla son que primos numeros los compuestos performance algorithm primes

performance - son - tabla de numeros compuestos



¿El código más eficiente para los primeros 10000 números primos? (29)

Quiero imprimir los primeros 10000 números primos. ¿Alguien puede darme el código más eficiente para esto? Aclaraciones:

  1. No importa si su código es ineficiente para n> 10000.
  2. El tamaño del código no importa.
  3. No puede simplemente codificar los valores de ninguna manera.

Aquí el código que hice:

enter code here #include <cmath> #include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; int main() { /* Enter your code here. Read input from STDIN. Print output to STDOUT*/ unsigned long int n; int prime(unsigned long int); scanf("%ld",&n); unsigned long int val; for(unsigned long int i=0;i<n;i++) { int flag=0; scanf("%ld",&val); flag=prime(val); if(flag==1) printf("yes/n"); else printf("no/n"); } return 0; } int prime(unsigned long int n) { if(n==2) return 1; else if (n == 1||n%2==0) return 0; for (unsigned long int i=3; i<=sqrt(n); i+=2) if (n%i == 0) return 0; return 1; }


Aquí está mi código que encuentra los primeros 10,000 primos en 0.049655 segundos en mi computadora portátil, los primeros 1,000,000 de primos en menos de 6 segundos y los primeros 2,000,000 en 15 segundos
Una pequeña explicación. Este método usa 2 técnicas para encontrar el número primo

  1. en primer lugar, cualquier número no primo es un compuesto de múltiplos de números primos, por lo que esta prueba de código dividiendo el número de prueba por números primos más pequeños en lugar de cualquier número, esto disminuye el cálculo al menos 10 veces para un número de 4 dígitos y aún más para un número mayor
  2. en segundo lugar, además de dividir entre primos, solo se divide por números primos que son más pequeños o iguales a la raíz del número que se está probando, lo que reduce aún más los cálculos, esto funciona porque cualquier número que sea mayor que la raíz del número tendrá un número de contraparte que tiene que ser más pequeño que la raíz del número, pero dado que ya hemos probado todos los números más pequeños que la raíz, por lo tanto, no necesitamos molestarnos con un número mayor que la raíz del número que se está probando.

Salida de muestra para el primer número primo de 10.000
https://drive.google.com/open?id=0B2QYXBiLI-lZMUpCNFhZeUphck0 https://drive.google.com/open?id=0B2QYXBiLI-lZbmRtTkZETnp6Ykk

Aquí está el código en lenguaje C, ingrese 1 y luego 10,000 para imprimir los primeros 10,000 primos.
Editar: Olvidé que esto contiene una biblioteca matemática, si estás en Windows o Visual Studio, eso debería estar bien, pero en Linux debes compilar el código usando el argumento -lm o el código puede no funcionar
Ejemplo: gcc -Wall -o "% e ""% f "-lm

#include <stdio.h> #include <math.h> #include <time.h> #include <limits.h> /* Finding prime numbers */ int main() { //pre-phase char d,w; int l,o; printf(" 1. Find first n number of prime numbers or Find all prime numbers smaller than n ?/n"); // this question helps in setting the limits on m or n value i.e l or o printf(" Enter 1 or 2 to get anwser of first or second question/n"); // decision making do { printf(" -->"); scanf("%c",&d); while ((w=getchar()) != ''/n'' && w != EOF); if ( d == ''1'') { printf("/n 2. Enter the target no. of primes you will like to find from 3 to 2,000,000 range/n -->"); scanf("%10d",&l); o=INT_MAX; printf(" Here we go!/n/n"); break; } else if ( d == ''2'' ) { printf("/n 2.Enter the limit under which to find prime numbers from 5 to 2,000,000 range/n -->"); scanf("%10d",&o); l=o/log(o)*1.25; printf(" Here we go!/n/n"); break; } else printf("/n Try again/n"); }while ( d != ''1'' || d != ''2'' ); clock_t start, end; double cpu_time_used; start = clock(); /* starting the clock for time keeping */ // main program starts here int i,j,c,m,n; /* i ,j , c and m are all prime array ''p'' variables and n is the number that is being tested */ int s,x; int p[ l ]; /* p is the array for storing prime numbers and l sets the array size, l was initialized in pre-phase */ p[1]=2; p[2]=3; p[3]=5; printf("%10dst:%10d/n%10dnd:%10d/n%10drd:%10d/n",1,p[1],2,p[2],3,p[3]); // first three prime are set for ( i=4;i<=l;++i ) /* this loop sets all the prime numbers greater than 5 in the p array to 0 */ p[i]=0; n=6; /* prime number testing begins with number 6 but this can lowered if you wish but you must remember to update other variables too */ s=sqrt(n); /* ''s'' does two things it stores the root value so that program does not have to calaculate it again and again and also it stores it in integer form instead of float*/ x=2; /* ''x'' is the biggest prime number that is smaller or equal to root of the number ''n'' being tested */ /* j ,x and c are related in this way, p[j] <= prime number x <= p[c] */ // the main loop begins here for ( m=4,j=1,c=2; m<=l && n <= o;) /* this condition checks if all the first ''l'' numbers of primes are found or n does not exceed the set limit o */ { // this will divide n by prime number in p[j] and tries to rule out non-primes if ( n%p[j]==0 ) { /* these steps execute if the number n is found to be non-prime */ ++n; /* this increases n by 1 and therefore sets the next number ''n'' to be tested */ s=sqrt(n); /* this calaulates and stores in ''s'' the new root of number ''n'' */ if ( p[c] <= s && p[c] != x ) /* ''The Magic Setting'' tests the next prime number candidate p[c] and if passed it updates the prime number x */ { x=p[c]; ++c; } j=1; /* these steps sets the next number n to be tested and finds the next prime number x if possible for the new number ''n'' and also resets j to 1 for the new cycle */ continue; /* and this restarts the loop for the new cycle */ } // confirmation test for the prime number candidate n else if ( n%p[j]!=0 && p[j]==x ) { /* these steps execute if the number is found to be prime */ p[m]=n; printf("%10dth:%10d/n",m,p[m]); ++n; s = sqrt(n); ++m; j=1; /* these steps stores and prints the new prime number and moves the ''m'' counter up and also sets the next number n to be tested and also resets j to 1 for the new cycle */ continue; /* and this restarts the loop */ /* the next number which will be a even and non-prime will trigger the magic setting in the next cycle and therfore we do not have to add another magic setting here*/ } ++j; /* increases p[j] to next prime number in the array for the next cycle testing of the number ''n'' */ // if the cycle reaches this point that means the number ''n'' was neither divisible by p[j] nor was it a prime number // and therfore it will test the same number ''n'' again in the next cycle with a bigger prime number } // the loops ends printf(" All done !!/n"); end = clock(); cpu_time_used = ((double) (end - start)) / CLOCKS_PER_SEC; printf(" Time taken : %lf sec/n",cpu_time_used); }


Como solo desea los primeros 10000 primos, en lugar de codificar un algoritmo complejo, le sugeriré lo siguiente

boolean isPrime(int n){ //even but is prime if(n==2) return true; //even numbers filtered already if(n==0 || n==1 || n%2==0) return false; // loop for checking only odd factors // i*i <= n (same as i<=sqrt(n), avoiding floating point calculations) for(int i=3 ; i*i <=n ; i+=2){ // if any odd factor divides n then its not a prime! if(n%i==0) return false; } // its prime now return true; }

ahora la llamada es excelente ya que la necesitas

for(int i=1 ; i<=1000 ; i++){ if(isPrime(i)){ //do something } }


Esta es una vieja pregunta, pero hay algo que todos están perdiendo ...

Para este primos, la división pequeño ensayo no es que lento ... sólo hay 25 números primos menores de 100. Con tan pocos números primos a prueba, y tan pequeños primos, podemos sacar un buen truco!

Si a es coprimo a b, entonces gcd ab = 1. Coprime. Palabra divertida Significa que no comparte ningún factor primo . Por lo tanto, podemos probar la divisibilidad por varios primos con una llamada GCD. ¿Cuántos? Bueno, el producto de los primeros 15 primos es menor que 2 ^ 64. Y el producto de los próximos 10 también es inferior a 2 ^ 64. Eso es todo lo que necesitamos. Pero ¿vale la pena?

Veamos:

check x = null $ filter ((==0) . (x `mod`)) $ [<primes up to 101>] Prelude> length $ filter check [101,103..85600] >>> 9975 (0.30 secs, 125,865,152 bytes a = 16294579238595022365 :: Word64 b = 14290787196698157718 pre = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97] primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) [99,101..85600] main = print $ length primes Prelude> main >>> 10000 (0.05 secs, 36,387,520 bytes)

Una mejora de 6 veces allí.

( length es forzar el cálculo de la lista. De forma predeterminada, Haskell imprime cosas de 1 carácter Unicode a la vez y, por lo tanto, imprimir la lista dominará el tiempo o dominará la cantidad de código real utilizada).

Por supuesto, esto se está ejecutando en GHCi, una respuesta que ejecuta código interpretado, en una computadora portátil vieja y no interpreta ninguno de estos números como int64 s o incluso BigInt s, ni lo hará incluso si lo solicita (bueno, puede forzarlo , pero es feo y realmente no ayuda). Está interpretando cada número allí como cosas generalizadas tipo Integer que se pueden especializar a algún tipo en particular a través de la búsqueda en el diccionario, y está atravesando una lista vinculada (que no se fusiona aquí ya que no se compila) 3 veces. Curiosamente, la fusión manual de los dos filtros en realidad lo ralentiza en el REPL.

Vamos a compilarlo:

.../Haskell/8.6/Testbed>Primes.exe +RTS -s 10000 606,280 bytes allocated in the heap Total time 0.000s ( 0.004s elapsed)

Usando el informe RTS porque Windows. Algunas líneas se recortaron porque no son relevantes: eran otros datos de GC, o medidas de solo una parte de la ejecución, y juntas suman 0.004s (o menos). Tampoco es un plegado constante, porque Haskell en realidad no hace mucho de eso. Si nos retiramos constantemente ( main = print 10000 ), obtenemos una asignación dramáticamente menor:

...Haskell/8.6/Testbed>Primes.exe +RTS -s 10000 47,688 bytes allocated in the heap Total time 0.000s ( 0.001s elapsed)

Literalmente lo suficiente para cargar el tiempo de ejecución, luego descubrir que no hay nada que hacer más que imprimir un número y salir. Agreguemos factorización de rueda:

wheel = scanl (+) 7 $ cycle [4, 2, 4, 2, 4, 6, 2, 6] primes = (pre ++) $ filter ((==1) . gcd a) $ filter ((==1) . gcd b) $ takeWhile (<85600) wheel Total time 0.000s ( 0.003s elapsed)

Reduzca aproximadamente 1/3 en relación con nuestra referencia de main = print 10000 , pero definitivamente hay espacio para una mayor optimización. De hecho, se detuvo para realizar un GC allí, por ejemplo, mientras que con los ajustes no debería haber ningún uso del montón. Por alguna razón, compilar para crear perfiles aquí en realidad reduce el tiempo de ejecución a 2 milisegundos:

Tue Nov 12 21:13 2019 Time and Allocation Profiling Report (Final) Primes.exe +RTS -p -RTS total time = 0.00 secs (2 ticks @ 1000 us, 1 processor) total alloc = 967,120 bytes (excludes profiling overheads)

Voy a dejar esto como está por ahora, estoy bastante seguro de que el jitter aleatorio está empezando a dominar.


He escrito esto usando python, ya que recién comencé a aprenderlo, y funciona perfectamente bien. El primer número 10.000 generado por este código es el mismo que se menciona en http://primes.utm.edu/lists/small/10000.txt . Para verificar si n es primo o no, divide n entre los números de 2 a sqrt(n) . Si alguno de este rango de números se divide perfectamente, n entonces no es primo.

import math print ("You want prime till which number??") a = input() a = int(a) x = 0 x = int(x) count = 1 print("2 is prime number") for c in range(3,a+1): b = math.sqrt(c) b = int(b) x = 0 for b in range(2,b+1): e = c % b e = int(e) if (e == 0): x = x+1 if (x == 0): print("%d is prime number" % c) count = count + 1 print("Total number of prime till %d is %d" % (a,count))


He estado trabajando en encontrar primos durante aproximadamente un año. Esto es lo que encontré como el más rápido:

import static java.lang.Math.sqrt; import java.io.PrintWriter; import java.io.File; public class finder { public static void main(String[] args) { primelist primes = new primelist(); primes.insert(3); primes.insert(5); File file = new File("C:/Users/Richard/Desktop/directory/file0024.txt"); file.getParentFile().mkdirs(); long time = System.nanoTime(); try{ PrintWriter printWriter = new PrintWriter ("file0024.txt"); int linenum = 0; printWriter.print("2"); printWriter.print (" , "); printWriter.print("3"); printWriter.print (" , "); int up; int down; for(int i =1; i<357913941;i++){// if(linenum%10000==0){ printWriter.println (""); linenum++; } down = i*6-1; if(primes.check(down)){ primes.insert(down); //System.out.println(i*6-1); printWriter.print ( down ); printWriter.print (" , "); linenum++; } up = i*6+1; if(primes.check(up)){ primes.insert(up); //System.out.println(i*6+1); printWriter.print ( up ); printWriter.print (" , "); linenum++; } } printWriter.println ("Time to execute"); printWriter.println (System.nanoTime()-time); //System.out.println(primes.length); printWriter.close (); }catch(Exception e){} } } class node{ node next; int x; public node (){ node next; x = 3; } public node(int z) { node next; x = z; } } class primelist{ node first; int length =0; node current; public void insert(int x){ node y = new node(x); if(current == null){ current = y; first = y; }else{ current.next = y; current = y; } length++; } public boolean check(int x){ int p = (int)sqrt(x); node y = first; for(int i = 0;i<length;i++){ if(y.x>p){ return true; }else if(x%y.x ==0){ return false; } y = y.next; } return true; } }

1902465190909 nano segundos para llegar a 2147483629 a partir de 2.


Paso un tiempo escribiendo un programa que calcula muchos primos y este es el código que utilizo para calcular un archivo de texto que contiene los primeros 1.000.000.000 primos. Está en alemán, pero la parte interesante es el método calcPrimes() . Los primos se almacenan en una matriz llamada Primzahlen. Recomiendo una CPU de 64 bits porque los cálculos son con enteros de 64 bits.

import java.io.*; class Primzahlengenerator { long[] Primzahlen; int LastUnknown = 2; public static void main(String[] args) { Primzahlengenerator Generator = new Primzahlengenerator(); switch(args.length) { case 0: //Wenn keine Argumente übergeben worden: Generator.printHelp(); //Hilfe ausgeben return; //Durchfallen verhindern case 1: try { Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()]; } catch (NumberFormatException e) { System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. /"Tausend/", sondern in Ziffern z.B. /"1000/" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben Generator.printHelp(); //Generelle Hilfe ausgeben return; } break;//dutchfallen verhindern case 2: switch (args[1]) { case "-l": System.out.println("Sie müsen auch eine Datei angeben!"); //Hilfemitteilung ausgeben Generator.printHelp(); //Generelle Hilfe ausgeben return; } break;//durchfallen verhindern case 3: try { Generator.Primzahlen = new long[Integer.decode(args[0]).intValue()]; } catch (NumberFormatException e) { System.out.println("Das erste Argument muss eine Zahl sein, und nicht als Wort z.B. /"Tausend/", sondern in Ziffern z.B. /"1000/" ausgedrückt werden.");//Hinweis, wie man die Argumente angeben muss ausgeben Generator.printHelp(); //Generelle Hilfe ausgeben return; } switch(args[1]) { case "-l": Generator.loadFromFile(args[2]);//Datei Namens des Inhalts von Argument 3 lesen, falls Argument 2 = "-l" ist break; default: Generator.printHelp(); break; } break; default: Generator.printHelp(); return; } Generator.calcPrims(); } void printHelp() { System.out.println("Sie müssen als erstes Argument angeben, die wieviel ersten Primzahlen sie berechnen wollen."); //Anleitung wie man das Programm mit Argumenten füttern muss System.out.println("Als zweites Argument können sie /"-l/" wählen, worauf die Datei, aus der die Primzahlen geladen werden sollen,"); System.out.println("folgen muss. Sie muss genauso aufgebaut sein, wie eine Datei Primzahlen.txt, die durch den Aufruf /"java Primzahlengenerator 1000 > Primzahlen.txt/" entsteht."); } void loadFromFile(String File) { // System.out.println("Lese Datei namens: /"" + File + "/""); try{ int x = 0; BufferedReader in = new BufferedReader(new FileReader(File)); String line; while((line = in.readLine()) != null) { Primzahlen[x] = new Long(line).longValue(); x++; } LastUnknown = x; } catch(FileNotFoundException ex) { System.out.println("Die angegebene Datei existiert nicht. Bitte geben sie eine existierende Datei an."); } catch(IOException ex) { System.err.println(ex); } catch(ArrayIndexOutOfBoundsException ex) { System.out.println("Die Datei enthält mehr Primzahlen als der reservierte Speicherbereich aufnehmen kann. Bitte geben sie als erstes Argument eine größere Zahl an,"); System.out.println("damit alle in der Datei enthaltenen Primzahlen aufgenommen werden können."); } /* for(long prim : Primzahlen) { System.out.println("" + prim); } */ //Hier soll code stehen, der von der Datei mit angegebenem Namen ( Wie diese aussieht einfach durch angeben von folgendem in cmd rausfinden: //java Primzahlengenerator 1000 > 1000Primzahlen.txt //da kommt ne textdatei, die die primzahlen enthält. mit Long.decode(String ziffern).longValue(); //erhält man das was an der entsprechenden stelle in das array soll. die erste zeile soll in [0] , die zweite zeile in [1] und so weiter. //falls im arry der platz aus geht(die exception kenn ich grad nich, aber mach mal: //int[] foo = { 1, 2, 3}; //int bar = foo[4]; //dann kriegst ne exception, das ist die gleiche die man kriegt, wenn im arry der platzt aus geht. } void calcPrims() { int PrimzahlNummer = LastUnknown; // System.out.println("LAstUnknown ist: " + LastUnknown); Primzahlen[0] = 2; Primzahlen[1] = 3; long AktuelleZahl = Primzahlen[PrimzahlNummer - 1]; boolean IstPrimzahl; // System.out.println("2"); // System.out.println("3"); int Limit = Primzahlen.length; while(PrimzahlNummer < Limit) { IstPrimzahl = true; double WurzelDerAktuellenZahl = java.lang.Math.sqrt(AktuelleZahl); for(int i = 1;i < PrimzahlNummer;i++) { if(AktuelleZahl % Primzahlen[i] == 0) { IstPrimzahl = false; break; } if(Primzahlen[i] > WurzelDerAktuellenZahl) break; } if(IstPrimzahl) { Primzahlen[PrimzahlNummer] = AktuelleZahl; PrimzahlNummer++; // System.out.println("" + AktuelleZahl); } AktuelleZahl = AktuelleZahl + 2; } for(long prim : Primzahlen) { System.out.println("" + prim); } } }


Puedo darte algunos consejos, tienes que implementarlo.

  1. Para cada número, obtenga la mitad de ese número. Por ejemplo, para verificar 21, solo obtenga el resto dividiéndolo del rango 2-10.
  2. Si es un número impar, solo divídalo por un número impar, y viceversa. Tal como para 21, divida solo con 3, 5, 7, 9.

El método más eficiente que llegué hasta ahora.


Usando Sieve of Eratosthenes, el cálculo es bastante más rápido en comparación con el algoritmo de números primos "conocidos".

Al usar el pseudocódigo de su wiki ( https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes ), puedo tener la solución en C #.

/// Get non-negative prime numbers until n using Sieve of Eratosthenes. public int[] GetPrimes(int n) { if (n <= 1) { return new int[] { }; } var mark = new bool[n]; for(var i = 2; i < n; i++) { mark[i] = true; } for (var i = 2; i < Math.Sqrt(n); i++) { if (mark[i]) { for (var j = (i * i); j < n; j += i) { mark[j] = false; } } } var primes = new List<int>(); for(var i = 3; i < n; i++) { if (mark[i]) { primes.Add(i); } } return primes.ToArray(); }

GetPrimes (100000000) toma 2s y 330ms.

NOTA : El valor puede variar según las especificaciones de hardware.


Usando el método Array.prototype.find () en Javascript. 2214,486 ms

function isPrime (number) { function prime(element) { let start = 2; while (start <= Math.sqrt(element)) { if (element % start++ < 1) { return false; } } return element > 1; } return [number].find(prime) } function logPrimes (n) { let count = 0 let nth = n let i = 0 while (count < nth) { if (isPrime(i)) { count++ console.log(''i'', i) //NOTE: If this line is ommited time to find 10,000th prime is 121.157ms if (count === nth) { console.log(''while i'', i) console.log(''count'', count) } } i++ } } console.time(logPrimes) logPrimes(10000) console.timeEnd(logPrimes) // 2214.486ms


@Matt: log (log (10000)) es ~ 2

Del artículo de Wikipedia (que usted citó) Sieve of Atkin :

Este tamiz calcula primos hasta N utilizando operaciones O(N/log log N) con solo N 1/2 + o (1) bits de memoria. Eso es un poco mejor que el tamiz de Eratóstenes que usa operaciones O (N) y bits de memoria O (N 1/2 (log log N) / log N) (AOL Atkin, DJ Bernstein, 2004) . Estas complejidades computacionales asintóticas incluyen optimizaciones simples, como la factorización de la rueda y la división del cálculo en bloques más pequeños.

Dadas las complejidades computacionales asintóticas a lo largo de O(N) (para Eratóstenes) y O(N/log(log(N))) (para Atkin) no podemos decir (para pequeños N=10_000 ) qué algoritmo si se implementa será más rápido.

Achim Flammenkamp escribió en El tamiz de Eratóstenes :

citado por:

@ num1

Para intervalos mayores de aproximadamente 10 ^ 9, seguramente para aquellos> 10 ^ 10, el Tamiz de Eratóstenes es superado por el Tamiz de Atkins y Bernstein, que utiliza formas cuadráticas binarias irreducibles. Consulte su documento para obtener información de antecedentes, así como el párrafo 5 del Ph.D. de W. Galway. tesis.

Por lo tanto, para 10_000 Sieve of Eratosthenes puede ser más rápido que Sieve of Atkin.

Para responder a OP, el código es prime_sieve.c (citado por num1 )


Adaptando y siguiendo desde GateKiller , aquí está la versión final que he usado.

public IEnumerable<long> PrimeNumbers(long number) { List<long> primes = new List<long>(); for (int i = 2; primes.Count < number; i++) { bool divisible = false; foreach (int num in primes) { if (i % num == 0) divisible = true; if (num > Math.Sqrt(i)) break; } if (divisible == false) primes.Add(i); } return primes; }

Básicamente es lo mismo, pero agregué la sugerencia "break on Sqrt" y cambié algunas de las variables para que me quedara mejor. (Estaba trabajando en Euler y necesitaba el número 10001)


Aquí está mi código VB 2008, que encuentra todos los primos <10,000,000 en 1 min 27 segundos en mi computadora portátil de trabajo. Omite números pares y solo busca números primos que son <el sqrt del número de prueba. Solo está diseñado para encontrar números primos de 0 a un valor sentinal.

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim TestNum As Integer Dim X As Integer Dim Z As Integer Dim TM As Single Dim TS As Single Dim TMS As Single Dim UnPrime As Boolean Dim Sentinal As Integer Button1.Text = "Thinking" Button1.Refresh() Sentinal = Val(SentinalTxt.Text) UnPrime = True Primes(0) = 2 Primes(1) = 3 Z = 1 TM = TimeOfDay.Minute TS = TimeOfDay.Second TMS = TimeOfDay.Millisecond For TestNum = 5 To Sentinal Step 2 Do While Primes(X) <> 0 And UnPrime And Primes(X) ^ 2 <= TestNum If Int(TestNum / Primes(X)) - (TestNum / Primes(X)) = 0 Then UnPrime = False End If X = X + 1 Loop If UnPrime = True Then X = X + 1 Z = Z + 1 Primes(Z) = TestNum End If UnPrime = True X = 0 Next Button1.Text = "Finished with " & Z TM = TimeOfDay.Minute - TM TS = TimeOfDay.Second - TS TMS = TimeOfDay.Millisecond - TMS ShowTime.Text = TM & ":" & TS & ":" & TMS End Sub


Aquí hay un Tamiz de Eratóstenes que escribí en PowerShell hace unos días. Tiene un parámetro para identificar la cantidad de números primos que se deben devolver.

# # generate a list of primes up to a specific target using a sieve of eratosthenes # function getPrimes { #sieve of eratosthenes, http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes param ($target,$count = 0) $sieveBound = [math]::ceiling(( $target - 1 ) / 2) #not storing evens so count is lower than $target $sieve = @($false) * $sieveBound $crossLimit = [math]::ceiling(( [math]::sqrt($target) - 1 ) / 2) for ($i = 1; $i -le $crossLimit; $i ++) { if ($sieve[$i] -eq $false) { $prime = 2 * $i + 1 write-debug "Found: $prime" for ($x = 2 * $i * ( $i + 1 ); $x -lt $sieveBound; $x += 2 * $i + 1) { $sieve[$x] = $true } } } $primes = @(2) for ($i = 1; $i -le $sieveBound; $i ++) { if($count -gt 0 -and $primes.length -ge $count) { break; } if($sieve[$i] -eq $false) { $prime = 2 * $i + 1 write-debug "Output: $prime" $primes += $prime } } return $primes }


Aquí hay una solución C ++, usando una forma de SoE:

#include <iostream> #include <deque> typedef std::deque<int> mydeque; void my_insert( mydeque & factors, int factor ) { int where = factor, count = factors.size(); while( where < count && factors[where] ) where += factor; if( where >= count ) factors.resize( where + 1 ); factors[ where ] = factor; } int main() { mydeque primes; mydeque factors; int a_prime = 3, a_square_prime = 9, maybe_prime = 3; int cnt = 2; factors.resize(3); std::cout << "2 3 "; while( cnt < 10000 ) { int factor = factors.front(); maybe_prime += 2; if( factor ) { my_insert( factors, factor ); } else if( maybe_prime < a_square_prime ) { std::cout << maybe_prime << " "; primes.push_back( maybe_prime ); ++cnt; } else { my_insert( factors, a_prime ); a_prime = primes.front(); primes.pop_front(); a_square_prime = a_prime * a_prime; } factors.pop_front(); } std::cout << std::endl; return 0; }

Tenga en cuenta que esta versión de Sieve puede calcular primos indefinidamente.

También tenga en cuenta, el TEL deque toma O(1) el tiempo para llevar a cabo push_back , pop_front y de acceso aleatorio, aunque subíndices.

La resize operación lleva O(n) tiempo, donde n es el número de elementos que se agregan. Debido a cómo estamos usando esta función, podemos tratar esta es una pequeña constante.

El cuerpo del while bucle my_insert se ejecuta O(log log n) veces, donde n es igual a la variable maybe_prime . Esto se debe a que la expresión de condición de la while evaluación se evaluará como verdadera una vez para cada factor primo de maybe_prime . Consulte " Función del divisor " en Wikipedia.

La multiplicación por el número de veces que my_insert se llama muestra que debería llevar O(n log log n) tiempo enumerar los n números primos ... lo cual es, como era de esperar, la complejidad temporal que se supone que tiene el Tamiz de Eratóstenes.

Sin embargo, si bien este código es eficiente, no es el más eficiente ... Sugeriría utilizar una biblioteca especializada para la generación de primos, como primesieve . Cualquier solución verdaderamente eficiente y bien optimizada tomará más código del que cualquiera quiera escribir en .


El algoritmo de cribado mencionado por BenGoldberg merece una mirada más cercana, no solo porque es muy elegante sino también porque ocasionalmente puede ser útil en la práctica (a diferencia del Tamiz de Atkin, que es un ejercicio puramente académico).

La idea básica detrás del algoritmo de deve tamizado es utilizar un tamiz deslizante pequeño que sea lo suficientemente grande como para contener al menos un múltiplo separado para cada uno de los factores primos ''activos'' actualmente, es decir, aquellos primos cuyo cuadrado no excede el número más bajo actualmente representado por el tamiz móvil. Otra diferencia con el SoE es que el tamiz de almacenamiento almacena los factores reales en las ranuras de los compuestos, no en los booleanos.

El algoritmo extiende el tamaño de la ventana del tamiz según sea necesario, lo que resulta en un rendimiento bastante uniforme en un amplio rango hasta que el tamiz comienza a exceder la capacidad del caché L1 de la CPU de manera apreciable. El último primo que se ajusta completamente es 25,237,523 (el primo 1,579,791), lo que da una cifra aproximada aproximada para el rango operativo razonable del algoritmo.

El algoritmo es bastante simple y robusto, e incluso tiene un rendimiento en un rango mucho más amplio que un Tamiz de Eratóstenes no segmentado. Este último es mucho más rápido siempre que su tamiz se ajuste completamente en el caché, es decir, hasta 2 ^ 16 para un tamiz de probabilidades con bools de tamaño byte. Luego, su rendimiento disminuye cada vez más, aunque siempre se mantiene significativamente más rápido que el deque a pesar de la desventaja (al menos en lenguajes compilados como C / C ++, Pascal o Java / C #).

Aquí hay una representación del algoritmo de criba de decantación en C #, porque encuentro que el lenguaje, a pesar de sus muchos defectos, es mucho más práctico para la creación de prototipos de algoritmos y experimentación que el C ++ extremadamente engorroso y pedante. ( LINQPad al LINQPad : estoy usando el LINQPad gratuito que hace posible sumergirse directamente, sin todo el desorden con la configuración de proyectos, archivos MAKE, directorios o cualquier otra cosa, y me da el mismo grado de interactividad que un indicador de Python).

C # no tiene un tipo de deque explícito, pero la List<int> simple List<int> funciona lo suficientemente bien como para demostrar el algoritmo.

Nota: esta versión no utiliza una deque para los primos, porque simplemente no tiene sentido sacar sqrt (n) de n primos. ¿De qué serviría eliminar 100 primos y dejar 9900? Al menos de esta manera, todos los primos se recopilan en un vector limpio, listo para su posterior procesamiento.

static List<int> deque_sieve (int n = 10000) { Trace.Assert(n >= 3); var primes = new List<int>() { 2, 3 }; var sieve = new List<int>() { 0, 0, 0 }; for (int sieve_base = 5, current_prime_index = 1, current_prime_squared = 9; ; ) { int base_factor = sieve[0]; if (base_factor != 0) { // the sieve base has a non-trivial factor - put that factor back into circulation mark_next_unmarked_multiple(sieve, base_factor); } else if (sieve_base < current_prime_squared) // no non-trivial factor -> found a non-composite { primes.Add(sieve_base); if (primes.Count == n) return primes; } else // sieve_base == current_prime_squared { // bring the current prime into circulation by injecting it into the sieve ... mark_next_unmarked_multiple(sieve, primes[current_prime_index]); // ... and elect a new current prime current_prime_squared = square(primes[++current_prime_index]); } // slide the sieve one step forward sieve.RemoveAt(0); sieve_base += 2; } }

Aquí están las dos funciones auxiliares:

static void mark_next_unmarked_multiple (List<int> sieve, int prime) { int i = prime, e = sieve.Count; while (i < e && sieve[i] != 0) i += prime; for ( ; e <= i; ++e) // no List<>.Resize()... sieve.Add(0); sieve[i] = prime; } static int square (int n) { return n * n; }

Probablemente, la forma más fácil de entender el algoritmo es imaginarlo como un Tamiz de Eratóstenes segmentado especial con un tamaño de segmento de 1, acompañado de un área de desbordamiento donde los cebadores se detienen cuando disparan sobre el extremo del segmento. Excepto que la celda única del segmento (también conocido como sieve[0] ) ya ha sido tamizada cuando llegamos a ella, porque se atropelló mientras era parte del área de desbordamiento.

El número representado por sieve[0] se mantiene en sieve_base , aunque sieve_front o window_base también serían buenos nombres que permiten establecer paralelos con el código de Ben o implementaciones de tamices segmentados / en ventana.

Si sieve[0] contiene un valor distinto de cero, entonces ese valor es un factor de sieve_base , que puede reconocerse como compuesto. Como la celda 0 es un múltiplo de ese factor, es fácil calcular su próximo salto, que es simplemente 0 más ese factor. Si esa celda ya está ocupada por otro factor, simplemente agregamos el factor nuevamente, y así sucesivamente hasta que encontremos un múltiplo del factor donde actualmente no hay otro factor estacionado (extendiendo el tamiz si es necesario). Esto también significa que no hay necesidad de almacenar las compensaciones de trabajo actuales de los distintos primos de un segmento al siguiente, como en un tamiz segmentado normal. Cada vez que encontramos un factor en el sieve[0] , su compensación de trabajo actual es 0.

La prima actual entra en juego de la siguiente manera. Un cebado solo puede convertirse en corriente después de su propia aparición en la secuencia (es decir, cuando se ha detectado como cebado, porque no está marcado con un factor), y seguirá siendo corriente hasta el momento exacto en que el sieve[0] alcance su cuadrado. Todos los múltiplos inferiores de este primo deben haberse eliminado debido a las actividades de los primos más pequeños, al igual que en un SoE normal. Pero ninguno de los primos más pequeños puede golpear el cuadrado, ya que el único factor del cuadrado es el primo en sí y aún no está en circulación en este punto. Eso explica las acciones tomadas por el algoritmo en el caso sieve_base == current_prime_squared (por cierto, sieve[0] == 0 ).

Ahora el caso sieve[0] == 0 && sieve_base < current_prime_squared se explica fácilmente: significa que sieve_base no puede ser un múltiplo de ninguno de los primos más pequeños que el primo actual, de lo contrario, se habría marcado como compuesto. Tampoco puedo ser un múltiplo mayor del primo actual, ya que su valor es menor que el cuadrado del primo actual. Por lo tanto, debe ser una nueva prima.

El algoritmo obviamente está inspirado en el Tamiz de Eratóstenes, pero igualmente obviamente es muy diferente. El tamiz de Eratóstenes deriva su velocidad superior de la simplicidad de sus operaciones elementales: una sola adición de índice y una tienda para cada paso de la operación es todo lo que hace durante largos períodos de tiempo.

Aquí hay un tamiz simple y no segmentado de Eratóstenes que normalmente uso para tamizar primos de factor en el rango de ushort, es decir, hasta 2 ^ 16. Para esta publicación, lo modifiqué para que funcione más allá de 2 ^ 16 sustituyendo int por ushort

static List<int> small_odd_primes_up_to (int n) { var result = new List<int>(); if (n < 3) return result; int sqrt_n_halved = (int)(Math.Sqrt(n) - 1) >> 1, max_bit = (n - 1) >> 1; var odd_composite = new bool[max_bit + 1]; for (int i = 3 >> 1; i <= sqrt_n_halved; ++i) if (!odd_composite[i]) for (int p = (i << 1) + 1, j = p * p >> 1; j <= max_bit; j += p) odd_composite[j] = true; result.Add(3); // needs to be handled separately because of the mod 3 wheel // read out the sieved primes for (int i = 5 >> 1, d = 1; i <= max_bit; i += d, d ^= 3) if (!odd_composite[i]) result.Add((i << 1) + 1); return result; }

Al tamizar los primeros 10000 primos, se excederá un caché L1 típico de 32 KiByte, pero la función sigue siendo muy rápida (fracción de milisegundo incluso en C #).

Si compara este código con el tamiz de extracción, es fácil ver que las operaciones del tamiz de extracción son mucho más complicadas, y no puede amortizar efectivamente su sobrecarga porque siempre hace el tramo más corto posible de cruces consecutivos. (exactamente un solo cruce, después de omitir todos los múltiplos que ya se han tachado).

Nota: el código C # usa int lugar de uint porque los compiladores más nuevos tienen la costumbre de generar código de calidad inferior para uint , probablemente para empujar a las personas hacia enteros firmados ... En la versión C ++ del código anterior, usé unsigned todas partes, naturalmente; el punto de referencia tenía que estar en C ++ porque quería que se basara en un tipo de deque supuestamente adecuado ( std::deque<unsigned> ; no hubo ganancia de rendimiento al usar unsigned short ). Estos son los números de mi computadora portátil Haswell (VC ++ 2015 / x64):

deque vs simple: 1.802 ms vs 0.182 ms deque vs simple: 1.836 ms vs 0.170 ms deque vs simple: 1.729 ms vs 0.173 ms

Nota: los tiempos de C # son casi exactamente el doble de los tiempos de C ++, lo cual es bastante bueno para C # y muestra que List<int> no se queda atrás, incluso si se abusa como una deque.

El código de tamiz simple todavía elimina la deque del agua, a pesar de que ya está operando más allá de su rango de trabajo normal (el tamaño de caché L1 excedió en un 50%, con el almacenamiento de caché correspondiente). La parte dominante aquí es la lectura de los números primos tamizados, y esto no se ve muy afectado por el problema de caché. En cualquier caso, la función se diseñó para tamizar los factores de factores, es decir, el nivel 0 en una jerarquía de tamices de 3 niveles, y normalmente solo debe devolver unos pocos cientos de factores o un bajo número de miles. De ahí su simplicidad.

El rendimiento podría mejorarse en más de un orden de magnitud mediante el uso de un tamiz segmentado y la optimización del código para extraer los cebadores tamizados (mod 3 escalonado y desenrollado dos veces, o mod 15 y desenrollar una vez), y aún más rendimiento podría exprimirse el código mediante el uso de una rueda mod 16 o mod 30 con todos los recortes (es decir, desenrollado completo para todos los residuos). Algo así se explica en mi respuesta a Buscar número primo en primer lugar en Revisión de código, donde se discutió un problema similar. Pero es difícil ver el punto de mejorar tiempos por debajo de milisegundos para una tarea única ...

Para poner las cosas un poco en perspectiva, aquí están los tiempos de C ++ para tamizar hasta 100,000,000:

deque vs simple: 1895.521 ms vs 432.763 ms deque vs simple: 1847.594 ms vs 429.766 ms deque vs simple: 1859.462 ms vs 430.625 ms

Por el contrario, un tamiz segmentado en C # con algunas campanas y silbatos hace el mismo trabajo en 95 ms (no hay tiempos de C ++ disponibles, ya que en este momento solo hago desafíos de código en C #).

Las cosas pueden verse decididamente diferentes en un lenguaje interpretado como Python, donde cada operación tiene un alto costo y el sobrecarga del intérprete eclipsa todas las diferencias debido a las ramas pronosticadas frente a las predicciones erróneas u operaciones de subciclo (turno, adición) vs. , y tal vez incluso la división). Eso está destinado a erosionar la ventaja de simplicidad del Tamiz de Eratóstenes, y esto podría hacer que la solución de Deque sea un poco más atractiva.

Además, muchos de los tiempos informados por otros encuestados en este tema probablemente estén dominados por el tiempo de salida . Esa es una guerra completamente diferente, donde mi arma principal es una clase simple como esta:

class CCWriter { const int SPACE_RESERVE = 11; // UInt31 + ''/n'' public static System.IO.Stream BaseStream; static byte[] m_buffer = new byte[1 << 16]; // need 55k..60k for a maximum-size range static int m_write_pos = 0; public static long BytesWritten = 0; // for statistics internal static ushort[] m_double_digit_lookup = create_double_digit_lookup(); internal static ushort[] create_double_digit_lookup () { var lookup = new ushort[100]; for (int lo = 0; lo < 10; ++lo) for (int hi = 0; hi < 10; ++hi) lookup[hi * 10 + lo] = (ushort)(0x3030 + (hi << 8) + lo); return lookup; } public static void Flush () { if (BaseStream != null && m_write_pos > 0) BaseStream.Write(m_buffer, 0, m_write_pos); BytesWritten += m_write_pos; m_write_pos = 0; } public static void WriteLine () { if (m_buffer.Length - m_write_pos < 1) Flush(); m_buffer[m_write_pos++] = (byte)''/n''; } public static void WriteLinesSorted (int[] values, int count) { int digits = 1, max_value = 9; for (int i = 0; i < count; ++i) { int x = values[i]; if (m_buffer.Length - m_write_pos < SPACE_RESERVE) Flush(); while (x > max_value) if (++digits < 10) max_value = max_value * 10 + 9; else max_value = int.MaxValue; int n = x, p = m_write_pos + digits, e = p + 1; m_buffer[p] = (byte)''/n''; while (n >= 10) { int q = n / 100, w = m_double_digit_lookup[n - q * 100]; n = q; m_buffer[--p] = (byte)w; m_buffer[--p] = (byte)(w >> 8); } if (n != 0 || x == 0) m_buffer[--p] = (byte)((byte)''0'' + n); m_write_pos = e; } } }

Eso toma menos de 1 ms para escribir 10000 números (ordenados). Es una clase estática porque está destinada a la inclusión textual en envíos de desafío de codificación, con un mínimo de alboroto y cero sobrecarga.

En general, descubrí que es mucho más rápido si el trabajo enfocado se realiza en lotes completos, lo que significa tamizar un cierto rango, luego extraer todos los primos en un vector / matriz, luego explotar toda la matriz, luego tamizar el siguiente rango y así sucesivamente, en lugar de mezclar todo junto. Tener funciones separadas enfocadas en tareas específicas también facilita la mezcla y combinación, permite la reutilización y facilita el desarrollo / prueba.


El siguiente código de Mathcad calculó el primer millón de primos en menos de 3 minutos.

Tenga en cuenta que esto sería utilizar dobles puntos de coma flotante para todos los números y se interpreta básicamente. Espero que la sintaxis sea clara.


El tamiz parece ser la respuesta incorrecta. El tamiz le da los números primos hasta un número N , no los primeros números primos N. Ejecute @Imran o @Andrew Szeto, y obtendrá los primos hasta N.

El tamiz podría seguir siendo utilizable si sigue probando tamices para números cada vez más grandes hasta que alcance un cierto tamaño de su conjunto de resultados, y use un almacenamiento en caché de los números ya obtenidos, pero creo que aún no sería más rápido que una solución como @ Pat''s .


En Haskell, podemos escribir casi palabra por palabra la definición matemática del tamiz de Eratóstenes, "los primos son números naturales superiores a 1 sin ningún número compuesto, donde los compuestos se encuentran por enumeración de los múltiplos de cada primo ":

import Data.List.Ordered (minus, union) primes = 2 : minus [3..] (foldr (/p r -> p*p : union [p*p+p, p*p+2*p..] r) [] primes)

primes !! 10000 primes !! 10000 es casi instantáneo.

Referencias

El código anterior se ajusta fácilmente para trabajar solo en probabilidades, primes = 2 : 3 : minus [5,7..] (foldr (/pr -> p*p : union [p*p+2*p, p*p+4*p..] r) [] (tail primes)) . La complejidad del tiempo se mejora mucho (hasta un factor de registro por encima del óptimo) al plegarse en una estructura similar a un árbol, y la complejidad del espacio se mejora drásticamente por la producción de primos en varias etapas , en

primes = 2 : _Y ( (3:) . sieve 5 . _U . map (/p -> [p*p, p*p+2*p..]) ) where _Y g = g (_Y g) -- non-sharing fixpoint combinator _U ((x:xs):t) = x : (union xs . _U . pairs) t -- ~= nub.sort.concat pairs (xs:ys:t) = union xs ys : pairs t sieve k s@(x:xs) | k < x = k : sieve (k+2) s -- ~= [k,k+2..]//s, | otherwise = sieve (k+2) xs -- when s⊂[k,k+2..]

(En Haskell, los paréntesis se usan para agrupar, una llamada a la función se indica solo por la yuxtaposición, (:) es un operador de contras para las listas y (.) Es un operador de composición funcional: (f . g) x = (/y -> f (gy)) x = f (gx) ).


En python

import gmpy p=1 for i in range(10000): p=gmpy.next_prime(p) print p


Esto no está estrictamente en contra de la restricción de codificación, pero se acerca terriblemente. ¿Por qué no descargar programáticamente esta lista e imprimirla en su lugar?

http://primes.utm.edu/lists/small/10000.txt


He adaptado el código encontrado en CodeProject para crear lo siguiente:

ArrayList primeNumbers = new ArrayList(); for(int i = 2; primeNumbers.Count < 10000; i++) { bool divisible = false; foreach(int number in primeNumbers) { if(i % number == 0) { divisible = true; } } if(divisible == false) { primeNumbers.Add(i); Console.Write(i + " "); } }

Probar esto en mi servidor ASP.NET tardó aproximadamente 1 minuto en ejecutarse.


No es eficiente en absoluto, pero puede usar una expresión regular para probar números primos.

/^1?$|^(11+?)/1+$/

Esto prueba si, para una cadena que consiste en k " 1 " s, k no es primo (es decir, si la cadena consiste en un " 1 " o cualquier número de " 1 " s que se puede expresar como un producto n -ary).


Recomiendo un tamiz, ya sea el Tamiz de Eratóstenes o el Tamiz de Atkin.

El tamiz o Eratóstenes es probablemente el método más intuitivo para encontrar una lista de números primos. Básicamente usted:

  1. Escriba una lista de números del 2 al límite que desee, digamos 1000.
  2. Tome el primer número que no está tachado (para la primera iteración este es 2) y tache todos los múltiplos de ese número de la lista.
  3. Repita el paso 2 hasta llegar al final de la lista. Todos los números que no se tachan son primos.

Obviamente, hay bastantes optimizaciones que se pueden hacer para que este algoritmo funcione más rápido, pero esta es la idea básica.

El tamiz de Atkin utiliza un enfoque similar, pero desafortunadamente no sé lo suficiente para explicárselo. Pero sí sé que el algoritmo que vinculé tarda 8 segundos en descubrir todos los números primos hasta 1000000000 en un antiguo Pentium II-350

Tamiz del código fuente de Eratóstenes: http://web.archive.org/web/20140705111241/http://primes.utm.edu/links/programs/sieves/Eratosthenes/C_source_code/

Tamiz del código fuente de Atkin: http://cr.yp.to/primegen.html


Usando GMP, uno podría escribir lo siguiente:

#include <stdio.h> #include <gmp.h> int main() { mpz_t prime; mpz_init(prime); mpz_set_ui(prime, 1); int i; char* num = malloc(4000); for(i=0; i<10000; i++) { mpz_nextprime(prime, prime); printf("%s, ", mpz_get_str(NULL,10,prime)); } }

En mi Macbook Pro de 2,33 GHz, se ejecuta de la siguiente manera:

time ./a.out > /dev/null real 0m0.033s user 0m0.029s sys 0m0.003s

Cálculo de 1,000,000 primos en la misma computadora portátil:

time ./a.out > /dev/null real 0m14.824s user 0m14.606s sys 0m0.086s

GMP está altamente optimizado para este tipo de cosas. A menos que realmente desee comprender los algoritmos escribiendo los suyos, le recomendamos que use libGMP bajo C.


GateKiller , ¿qué tal si agrega un break a eso if en el bucle foreach ? Eso aceleraría mucho las cosas porque si como 6 es divisible por 2, no necesita verificar con 3 y 5. (De todos modos, votaría su solución si tuviera suficiente reputación :-) ...)

ArrayList primeNumbers = new ArrayList(); for(int i = 2; primeNumbers.Count < 10000; i++) { bool divisible = false; foreach(int number in primeNumbers) { if(i % number == 0) { divisible = true; break; } } if(divisible == false) { primeNumbers.Add(i); Console.Write(i + " "); } }


El tamiz de Atkin es probablemente lo que está buscando, su tiempo de ejecución de límite superior es O (N / log log N).

Si solo ejecuta los números 1 más y 1 menos que los múltiplos de 6, podría ser aún más rápido, ya que todos los números primos superiores a 3 están a 1 de un múltiplo de seis. Recurso para mi declaración


Tamiz de Eratóstenes es el camino a seguir, debido a su simplicidad y velocidad. Mi implementación en C

#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <math.h> int main(void) { unsigned int lim, i, j; printf("Find primes upto: "); scanf("%d", &lim); lim += 1; bool *primes = calloc(lim, sizeof(bool)); unsigned int sqrtlim = sqrt(lim); for (i = 2; i <= sqrtlim; i++) if (!primes[i]) for (j = i * i; j < lim; j += i) primes[j] = true; printf("/nListing prime numbers between 2 and %d:/n/n", lim - 1); for (i = 2; i < lim; i++) if (!primes[i]) printf("%d/n", i); return 0; }

Tiempo de CPU para encontrar primos (en Pentium Dual Core E2140 1.6 GHz, usando un solo núcleo)

~ 4s para lim = 100,000,000


using System; namespace ConsoleApplication2 { class Program { static void Main(string[] args) { int n, i = 3, j, c; Console.WriteLine("Please enter your integer: "); n = Convert.ToInt32(Console.ReadLine()); if (n >= 1) { Console.WriteLine("First " + n + " Prime Numbers are"); Console.WriteLine("2"); } for(j=2;j<=n;) { for(c=2;c<=i-1;c++) { if(i%c==0) break; } if(c==i) { Console.WriteLine(i); j++; } i++; } Console.Read(); } } }