web-dev-qa-db-fra.com

La façon la plus élégante de générer des nombres premiers

Quelle est la manière la plus élégante d'implémenter cette fonction:

ArrayList generatePrimes(int n)

Cette fonction génère les premiers n nombres premiers (edit: where n>1), Donc generatePrimes(5) renverra un ArrayList avec {2, 3, 5, 7, 11}. (Je fais cela en C #, mais je suis satisfait d'une Java - ou de tout autre langage similaire d'ailleurs (donc pas Haskell)).

Je sais comment écrire cette fonction, mais quand je l'ai fait la nuit dernière, elle n'a pas été aussi agréable que je l'espérais. Voici ce que j'ai trouvé:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();
    primes.Add(2);
    primes.Add(3);
    while (primes.Count < toGenerate)
    {
        int nextPrime = (int)(primes[primes.Count - 1]) + 2;
        while (true)
        {
            bool isPrime = true;
            foreach (int n in primes)
            {
                if (nextPrime % n == 0)
                {
                    isPrime = false;
                    break;
                }
            }
            if (isPrime)
            {
                break;
            }
            else
            {
                nextPrime += 2;
            }
        }
        primes.Add(nextPrime);
    }
    return primes;
}

Je ne suis pas trop préoccupé par la vitesse, même si je ne veux pas qu'elle soit manifestement inefficace. Je ne me soucie pas de la méthode utilisée (naïf ou tamis ou autre), mais je veux que ce soit assez court et évident comment cela fonctionne.

Edit : Merci à tous ceux qui ont répondu, bien que beaucoup n'aient pas répondu à ma question. Pour réitérer, je voulais un morceau de code propre et agréable qui génère une liste de nombres premiers. Je sais déjà comment le faire de différentes manières, mais je suis enclin à écrire du code qui n'est pas aussi clair qu'il pourrait l'être. Dans ce fil, quelques bonnes options ont été proposées:

  • Une version plus agréable de ce que j'avais à l'origine (Peter Smit, jmservera et Rekreativc)
  • Une mise en œuvre très propre du tamis d'Eratosthène (starblue)
  • Utilisez BigIntegers et nextProbablePrime de Java pour du code très simple, même si je ne peux pas imaginer qu'il soit particulièrement efficace (dfa)
  • Utilisez LINQ pour générer paresseusement la liste des nombres premiers (Maghis)
  • Mettez beaucoup de nombres premiers dans un fichier texte et lisez-les si nécessaire (darin)

Edit 2 : J'ai implémenté en C # quelques méthodes données ici, et une autre méthode non mentionnée ici. Ils trouvent tous le premier n amorce efficacement (et j'ai une méthode décente pour trouver la limite à fournir aux tamis).

81
David Johnstone

Un grand merci à tous ceux qui ont donné des réponses utiles. Voici mes implémentations de quelques méthodes différentes pour trouver les premiers n nombres premiers en C #. Les deux premières méthodes sont à peu près ce qui a été publié ici. (Les noms des affiches sont à côté du titre.) Je prévois de faire le tamis d'Atkin un jour, bien que je soupçonne que ce ne sera pas aussi simple que les méthodes ici actuellement. Si quelqu'un peut voir un moyen d'améliorer l'une de ces méthodes, j'aimerais savoir :-)

Méthode standard ( Peter Smit , jmservera , Rekreativc )

Le premier nombre premier est 2. Ajoutez-le à une liste de nombres premiers. Le nombre premier suivant est le nombre suivant qui n'est divisible par aucun nombre de cette liste.

public static List<int> GeneratePrimesNaive(int n)
{
    List<int> primes = new List<int>();
    primes.Add(2);
    int nextPrime = 3;
    while (primes.Count < n)
    {
        int sqrt = (int)Math.Sqrt(nextPrime);
        bool isPrime = true;
        for (int i = 0; (int)primes[i] <= sqrt; i++)
        {
            if (nextPrime % primes[i] == 0)
            {
                isPrime = false;
                break;
            }
        }
        if (isPrime)
        {
            primes.Add(nextPrime);
        }
        nextPrime += 2;
    }
    return primes;
}

Ceci a été optimisé en testant uniquement la divisibilité jusqu'à la racine carrée du nombre testé; et en testant uniquement les nombres impairs. Cela peut encore être optimisé en testant uniquement les numéros de la forme 6k+[1, 5], ou 30k+[1, 7, 11, 13, 17, 19, 23, 29] ou ainsi de suite .

Tamis d'Ératosthène ( bleu étoile )

Ceci trouve tous les nombres premiers à k . Pour faire une liste des premiers n nombres premiers, nous devons d'abord approximer la valeur du n ème nombre premier. La méthode suivante, comme décrit ici , fait cela.

public static int ApproximateNthPrime(int nn)
{
    double n = (double)nn;
    double p;
    if (nn >= 7022)
    {
        p = n * Math.Log(n) + n * (Math.Log(Math.Log(n)) - 0.9385);
    }
    else if (nn >= 6)
    {
        p = n * Math.Log(n) + n * Math.Log(Math.Log(n));
    }
    else if (nn > 0)
    {
        p = new int[] { 2, 3, 5, 7, 11 }[nn - 1];
    }
    else
    {
        p = 0;
    }
    return (int)p;
}

// Find all primes up to and including the limit
public static BitArray SieveOfEratosthenes(int limit)
{
    BitArray bits = new BitArray(limit + 1, true);
    bits[0] = false;
    bits[1] = false;
    for (int i = 0; i * i <= limit; i++)
    {
        if (bits[i])
        {
            for (int j = i * i; j <= limit; j += i)
            {
                bits[j] = false;
            }
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfEratosthenes(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfEratosthenes(limit);
    List<int> primes = new List<int>();
    for (int i = 0, found = 0; i < limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(i);
            found++;
        }
    }
    return primes;
}

Tamis de Sundaram

Je n'ai découvert que ce tamis récemment, mais il peut être implémenté tout simplement. Mon implémentation n'est pas aussi rapide que le tamis d'Eratosthène, mais elle est nettement plus rapide que la méthode naïve.

public static BitArray SieveOfSundaram(int limit)
{
    limit /= 2;
    BitArray bits = new BitArray(limit + 1, true);
    for (int i = 1; 3 * i + 1 < limit; i++)
    {
        for (int j = 1; i + j + 2 * i * j <= limit; j++)
        {
            bits[i + j + 2 * i * j] = false;
        }
    }
    return bits;
}

public static List<int> GeneratePrimesSieveOfSundaram(int n)
{
    int limit = ApproximateNthPrime(n);
    BitArray bits = SieveOfSundaram(limit);
    List<int> primes = new List<int>();
    primes.Add(2);
    for (int i = 1, found = 1; 2 * i + 1 <= limit && found < n; i++)
    {
        if (bits[i])
        {
            primes.Add(2 * i + 1);
            found++;
        }
    }
    return primes;
}
34
David Johnstone

Utilisez l'estimation

pi(n) = n / log(n)

pour le nombre de nombres premiers jusqu'à n pour trouver une limite, puis utilisez un tamis. L'estimation sous-estime le nombre de nombres premiers jusqu'à n quelque peu, donc le tamis sera légèrement plus grand que nécessaire, ce qui est correct.

C'est mon standard Java tamis, calcule le premier million de nombres premiers en environ une seconde sur un ordinateur portable normal:

public static BitSet computePrimes(int limit)
{
    final BitSet primes = new BitSet();
    primes.set(0, false);
    primes.set(1, false);
    primes.set(2, limit, true);
    for (int i = 0; i * i < limit; i++)
    {
        if (primes.get(i))
        {
            for (int j = i * i; j < limit; j += i)
            {
                primes.clear(j);
            }
        }
    }
    return primes;
}
47
starblue

Ressuscitant une vieille question, mais je suis tombée dessus en jouant avec LINQ.

Ce code nécessite .NET4.0 ou .NET3.5 avec des extensions parallèles

public List<int> GeneratePrimes(int n) {
    var r = from i in Enumerable.Range(2, n - 1).AsParallel()
            where Enumerable.Range(2, (int)Math.Sqrt(i)).All(j => i % j != 0)
            select i;
    return r.ToList();
}
11
spookycoder

Vous êtes sur la bonne voie.

Certains commentaires

  • primes.Add (3); fait que cette fonction ne fonctionne pas pour nombre = 1

  • Vous n'avez pas à tester la division avec des nombres premiers plus grands que la racine carrée du nombre à tester.

Code suggéré:

ArrayList generatePrimes(int toGenerate)
{
    ArrayList primes = new ArrayList();

    if(toGenerate > 0) primes.Add(2);

    int curTest = 3;
    while (primes.Count < toGenerate)
    {

        int sqrt = (int) Math.sqrt(curTest);

        bool isPrime = true;
        for (int i = 0; i < primes.Count && primes.get(i) <= sqrt; ++i)
        {
            if (curTest % primes.get(i) == 0)
            {
                isPrime = false;
                break;
            }
        }

        if(isPrime) primes.Add(curTest);

        curTest +=2
    }
    return primes;
}
9
Peter Smit

vous devriez jeter un œil à nombres premiers probables . Jetez un œil en particulier à Algorithmes Randomisés et Test de primalité de Miller – Rabin .

Par souci d'exhaustivité, vous pouvez simplement utiliser Java.math.BigInteger :

public class PrimeGenerator implements Iterator<BigInteger>, Iterable<BigInteger> {

    private BigInteger p = BigInteger.ONE;

    @Override
    public boolean hasNext() {
        return true;
    }

    @Override
    public BigInteger next() {
        p = p.nextProbablePrime();
        return p;
    }

    @Override
    public void remove() {
        throw new UnsupportedOperationException("Not supported.");
    }

    @Override
    public Iterator<BigInteger> iterator() {
        return this;
    }
}

@Test
public void printPrimes() {
    for (BigInteger p : new PrimeGenerator()) {
        System.out.println(p);
    }
}
8
dfa

En aucun cas efficace, mais peut-être le plus lisible:

public static IEnumerable<int> GeneratePrimes()
{
   return Range(2).Where(candidate => Range(2, (int)Math.Sqrt(candidate)))
                                     .All(divisor => candidate % divisor != 0));
}

avec:

public static IEnumerable<int> Range(int from, int to = int.MaxValue)
{
   for (int i = from; i <= to; i++) yield return i;
}

En fait, juste une variation de certains messages ici avec une mise en forme agréable.

6
RaphM

Utilisez un prime générateur de nombres pour créer primes.txt puis:

class Program
{
    static void Main(string[] args)
    {
        using (StreamReader reader = new StreamReader("primes.txt"))
        {
            foreach (var prime in GetPrimes(10, reader))
            {
                Console.WriteLine(prime);
            }
        }
    }

    public static IEnumerable<short> GetPrimes(short upTo, StreamReader reader)
    {
        int count = 0;
        string line = string.Empty;
        while ((line = reader.ReadLine()) != null && count++ < upTo)
        {
            yield return short.Parse(line);
        }
    }
}

Dans ce cas, j'utilise Int16 dans la signature de la méthode, donc mon fichier primes.txt contient des nombres de 0 à 32767. Si vous souhaitez étendre cela à Int32 ou Int64, votre primes.txt pourrait être considérablement plus grand.

4
Darin Dimitrov

Voici une implémentation de Sieve of Eratosthenes en C #:

    IEnumerable<int> GeneratePrimes(int n)
    {
        var values = new Numbers[n];

        values[0] = Numbers.Prime;
        values[1] = Numbers.Prime;

        for (int outer = 2; outer != -1; outer = FirstUnset(values, outer))
        {
            values[outer] = Numbers.Prime;

            for (int inner = outer * 2; inner < values.Length; inner += outer)
                values[inner] = Numbers.Composite;
        }

        for (int i = 2; i < values.Length; i++)
        {
            if (values[i] == Numbers.Prime)
                yield return i;
        }
    }

    int FirstUnset(Numbers[] values, int last)
    {
        for (int i = last; i < values.Length; i++)
            if (values[i] == Numbers.Unset)
                return i;

        return -1;
    }

    enum Numbers
    {
        Unset,
        Prime,
        Composite
    }
4
Alon Gubkin

Je sais que vous avez demandé une solution non Haskell, mais je l'inclus ici car elle se rapporte à la question et Haskell est également magnifique pour ce type de chose.

module Prime where

primes :: [Integer]
primes = 2:3:primes'
  where
    -- Every prime number other than 2 and 3 must be of the form 6k + 1 or 
    -- 6k + 5. Note we exclude 1 from the candidates and mark the next one as
    -- prime (6*0+5 == 5) to start the recursion.
    1:p:candidates = [6*k+r | k <- [0..], r <- [1,5]]
    primes'        = p : filter isPrime candidates
    isPrime n      = all (not . divides n) $ takeWhile (\p -> p*p <= n) primes'
    divides n p    = n `mod` p == 0
4
grom

Je peux offrir la solution C # suivante. Ce n'est en aucun cas rapide, mais il est très clair sur ce qu'il fait.

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    for (int n = 3; n <= limit; n += 2)
    {
        Int32 sqrt = (Int32)Math.Sqrt(n);

        if (primes.TakeWhile(p => p <= sqrt).All(p => n % p != 0))
        {
            primes.Add(n);
        }
    }

    return primes;
}

J'ai omis tous les contrôles - si la limite est négative ou inférieure à deux (pour le moment, la méthode retournera toujours au moins deux comme premier). Mais c'est facile à résoudre.

MISE À JOUR

Avec les deux méthodes d'extension suivantes

public static void Do<T>(this IEnumerable<T> collection, Action<T> action)
{
    foreach (T item in collection)
    {
        action(item);
    }
}

public static IEnumerable<Int32> Range(Int32 start, Int32 end, Int32 step)
{
    for (int i = start; i < end; i += step)
    }
        yield return i;
    }
}

vous pouvez le réécrire comme suit.

public static List<Int32> GetPrimes(Int32 limit)
{
    List<Int32> primes = new List<Int32>() { 2 };

    Range(3, limit, 2)
        .Where(n => primes
            .TakeWhile(p => p <= Math.Sqrt(n))
            .All(p => n % p != 0))
        .Do(n => primes.Add(n));

    return primes;
}

Il est moins efficace (car la racine carrée est réévaluée assez souvent) mais c'est un code encore plus propre. Il est possible de réécrire le code pour énumérer paresseusement les nombres premiers, mais cela encombrera un peu le code.

4
Daniel Brückner

Copyrights 2009 par St.Wittum 13189 Berlin ALLEMAGNE sous licence CC-BY-SA https://creativecommons.org/licenses/by-sa/3.0/

La façon la plus simple mais la plus élégante de calculer TOUS LES PRIMES serait la suivante, mais cette méthode est lente et les coûts de mémoire sont beaucoup plus élevés pour les nombres plus élevés, car en utilisant la fonction faculté (!) ... mais cela démontre une variation de Wilson Theoreme dans une application pour générer tous les nombres premiers par algorithme implémenté en Python

#!/usr/bin/python
f=1 # 0!
p=2 # 1st prime
while True:
    if f%p%2:
        print p
    p+=1
    f*=(p-2)
4
Steffen Wittum

En utilisant votre même algorithme, vous pouvez le faire un peu plus court:

List<int> primes=new List<int>(new int[]{2,3});
for (int n = 5; primes.Count< numberToGenerate; n+=2)
{
  bool isPrime = true;
  foreach (int prime in primes)
  {
    if (n % prime == 0)
    {
      isPrime = false;
      break;
    }
  }
  if (isPrime)
    primes.Add(n);
}
3
jmservera

J'ai écrit une implémentation simple d'Eratosthène en c # à l'aide de LINQ.

Malheureusement, LINQ ne fournit pas une séquence infinie d'entiers, vous devez donc utiliser int.MaxValue :(

J'ai dû mettre en cache dans un type anonyme le sqrt candidat pour éviter de le calculer pour chaque nombre premier mis en cache (ça a l'air un peu moche).

J'utilise une liste des nombres premiers précédents jusqu'au sqrt du candidat

cache.TakeWhile(c => c <= candidate.Sqrt)

et vérifier chaque Int à partir de 2 contre lui

.Any(cachedPrime => candidate.Current % cachedPrime == 0)

Voici le code:

static IEnumerable<int> Primes(int count)
{
    return Primes().Take(count);
}

static IEnumerable<int> Primes()
{
    List<int> cache = new List<int>();

    var primes = Enumerable.Range(2, int.MaxValue - 2).Select(candidate => new 
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}

Une autre optimisation consiste à éviter de vérifier les nombres pairs et à n'en renvoyer que 2 avant de créer la liste. De cette façon, si la méthode appelante ne demande qu'un nombre premier, cela évitera tout le désordre:

static IEnumerable<int> Primes()
{
    yield return 2;
    List<int> cache = new List<int>() { 2 };

    var primes = Enumerable.Range(3, int.MaxValue - 3)
        .Where(candidate => candidate % 2 != 0)
        .Select(candidate => new
    {
        Sqrt = (int)Math.Sqrt(candidate), // caching sqrt for performance
        Current = candidate
    }).Where(candidate => !cache.TakeWhile(c => c <= candidate.Sqrt)
            .Any(cachedPrime => candidate.Current % cachedPrime == 0))
            .Select(p => p.Current);

    foreach (var prime in primes)
    {
        cache.Add(prime);
        yield return prime;
    }
}
3
Maghis

C'est le plus élégant auquel je puisse penser à court terme.

ArrayList generatePrimes(int numberToGenerate)
{
    ArrayList rez = new ArrayList();

    rez.Add(2);
    rez.Add(3);

    for(int i = 5; rez.Count <= numberToGenerate; i+=2)
    {
        bool prime = true;
        for (int j = 2; j < Math.Sqrt(i); j++)
        {
            if (i % j == 0)
            {
                    prime = false;
                    break;
            }
        }
        if (prime) rez.Add(i);
    }

    return rez;
}

J'espère que cela vous aidera à vous donner une idée. Je suis sûr que cela peut être optimisé, mais cela devrait vous donner une idée de la façon dont votre version pourrait être rendue plus élégante.

EDIT: Comme indiqué dans les commentaires, cet algorithme renvoie en effet des valeurs erronées pour numberToGenerate <2. Je veux juste souligner que je n'essayais pas de lui publier une excellente méthode pour générer des nombres premiers (regardez à la réponse d'Henri pour cela), je montrais avec mépris comment sa méthode pouvait être rendue plus élégante.

1
David Božjak

Essayez cette requête LINQ, elle génère des nombres premiers comme vous vous y attendiez

        var NoOfPrimes= 5;
        var GeneratedPrime = Enumerable.Range(1, int.MaxValue)
          .Where(x =>
            {
                 return (x==1)? false:
                        !Enumerable.Range(1, (int)Math.Sqrt(x))
                        .Any(z => (x % z == 0 && x != z && z != 1));
            }).Select(no => no).TakeWhile((val, idx) => idx <= NoOfPrimes-1).ToList();
1
RameshVel

Pour le rendre plus élégant, vous devez refactoriser votre test IsPrime dans une méthode distincte et gérer le bouclage et les incréments en dehors de cela.

1
cjk

Je l'ai fait en Java en utilisant une bibliothèque fonctionnelle que j'ai écrite, mais comme ma bibliothèque utilise les mêmes concepts que les énumérations, je suis sûr que le code est adaptable:

Iterable<Integer> numbers = new Range(1, 100);
Iterable<Integer> primes = numbers.inject(numbers, new Functions.Injecter<Iterable<Integer>, Integer>()
{
    public Iterable<Integer> call(Iterable<Integer> numbers, final Integer number) throws Exception
    {
        // We don't test for 1 which is implicit
        if ( number <= 1 )
        {
            return numbers;
        }
        // Only keep in numbers those that do not divide by number
        return numbers.reject(new Functions.Predicate1<Integer>()
        {
            public Boolean call(Integer n) throws Exception
            {
                return n > number && n % number == 0;
            }
        });
    }
});
1
Vincent Robert

Personnellement, je pense que c'est une implémentation assez courte et propre (Java):

static ArrayList<Integer> getPrimes(int numPrimes) {
    ArrayList<Integer> primes = new ArrayList<Integer>(numPrimes);
    int n = 2;
    while (primes.size() < numPrimes) {
        while (!isPrime(n)) { n++; }
        primes.add(n);
        n++;
    }
    return primes;
}

static boolean isPrime(int n) {
    if (n < 2) { return false; }
    if (n == 2) { return true; }
    if (n % 2 == 0) { return false; }
    int d = 3;
    while (d * d <= n) {
        if (n % d == 0) { return false; }
        d += 2;
    }
    return true;
}
1
Zarkonnen

En utilisant la programmation basée sur les flux dans Java fonctionnel , j'ai trouvé ce qui suit. Le type Natural est essentiellement un BigInteger> = 0.

public static Stream<Natural> sieve(final Stream<Natural> xs)
{ return cons(xs.head(), new P1<Stream<Natural>>()
  { public Stream<Natural> _1()
    { return sieve(xs.tail()._1()
                   .filter($(naturalOrd.equal().eq(ZERO))
                           .o(mod.f(xs.head())))); }}); }

public static final Stream<Natural> primes
  = sieve(forever(naturalEnumerator, natural(2).some()));

Vous avez maintenant une valeur que vous pouvez transporter, qui est un flux infini de nombres premiers. Vous pouvez faire des choses comme ça:

// Take the first n primes
Stream<Natural> nprimes = primes.take(n);

// Get the millionth prime
Natural mprime = primes.index(1000000);

// Get all primes less than n
Stream<Natural> pltn = primes.takeWhile(naturalOrd.lessThan(n));

Une explication du tamis:

  1. Supposez que le premier nombre dans le flux d'arguments est premier et placez-le à l'avant du flux de retour. Le reste du flux de retour est un calcul à produire uniquement sur demande.
  2. Si quelqu'un demande le reste du flux, appelez tamis sur le reste du flux d'arguments, en filtrant les nombres divisibles par le premier nombre (le reste de la division est zéro).

Vous devez avoir les importations suivantes:

import fj.P1;
import static fj.FW.$;
import static fj.data.Enumerator.naturalEnumerator;
import fj.data.Natural;
import static fj.data.Natural.*;
import fj.data.Stream;
import static fj.data.Stream.*;
import static fj.pre.Ord.naturalOrd;
1
Apocalisp

Voici un exemple de code python qui affiche la somme de tous les nombres premiers inférieurs à deux millions:

from math import *

limit = 2000000
sievebound = (limit - 1) / 2
# sieve only odd numbers to save memory
# the ith element corresponds to the odd number 2*i+1
sieve = [False for n in xrange(1, sievebound + 1)]
crosslimit = (int(ceil(sqrt(limit))) - 1) / 2
for i in xrange(1, crosslimit):
    if not sieve[i]:
        # if p == 2*i + 1, then
        #   p**2 == 4*(i**2) + 4*i + 1
        #        == 2*i * (i + 1)
        for j in xrange(2*i * (i + 1), sievebound, 2*i + 1):
            sieve[j] = True
sum = 2
for i in xrange(1, sievebound):
    if not sieve[i]:
        sum = sum + (2*i+1)
print sum
1
grom
// Create a test range
IEnumerable<int> range = Enumerable.Range(3, 50 - 3);

// Sequential prime number generator
var primes_ = from n in range
     let w = (int)Math.Sqrt(n)
     where Enumerable.Range(2, w).All((i) => n % i > 0)
     select n;

// Note sequence of output:
// 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
foreach (var p in primes_)
    Trace.Write(p + ", ");
Trace.WriteLine("");
1
Raj Parmar

La méthode la plus simple est l'essai et l'erreur: vous essayez si un nombre entre 2 et n-1 divise votre candidat premier n.
Les premiers raccourcis sont bien sûr a) vous n'avez qu'à vérifier les nombres impairs, et b) vous n'avez qu'à vérifier les diviseurs jusqu'à sqrt (n).

Dans votre cas, où vous générez également tous les nombres premiers précédents dans le processus, vous n'avez qu'à vérifier si l'un des nombres premiers de votre liste, jusqu'à sqrt (n), divise n.
Devrait être le plus rapide que vous pouvez obtenir pour votre argent :-)

modifier
Ok, code, tu l'as demandé. Mais je vous préviens :-), ceci est du code Delphi rapide et sale de 5 minutes:

procedure TForm1.Button1Click(Sender: TObject);
const
  N = 100;
var
  PrimeList: TList;
  I, J, SqrtP: Integer;
  Divides: Boolean;
begin
  PrimeList := TList.Create;
  for I := 2 to N do begin
    SqrtP := Ceil(Sqrt(I));
    J := 0;
    Divides := False;
    while (not Divides) and (J < PrimeList.Count) 
                        and (Integer(PrimeList[J]) <= SqrtP) do begin
      Divides := ( I mod Integer(PrimeList[J]) = 0 );
      inc(J);
    end;
    if not Divides then
      PrimeList.Add(Pointer(I));
  end;
  // display results
  for I := 0 to PrimeList.Count - 1 do
    ListBox1.Items.Add(IntToStr(Integer(PrimeList[I])));
  PrimeList.Free;
end;
0
stevenvh

Essayez ce code.

protected bool isPrimeNubmer(int n)
    {
        if (n % 2 == 0)
            return false;
        else
        {
            int j = 3;
            int k = (n + 1) / 2 ;

            while (j <= k)
            {
                if (n % j == 0)
                    return false;
                j = j + 2;
            }
            return true;
        }
    }
    protected void btn_primeNumbers_Click(object sender, EventArgs e)
    {
        string time = "";
        lbl_message.Text = string.Empty;
        int num;

        StringBuilder builder = new StringBuilder();

        builder.Append("<table><tr>");
        if (int.TryParse(tb_number.Text, out num))
        {
            if (num < 0)
                lbl_message.Text = "Please enter a number greater than or equal to 0.";
            else
            {
                int count = 1;
                int number = 0;
                int cols = 11;

                var watch = Stopwatch.StartNew();

                while (count <= num)
                {
                    if (isPrimeNubmer(number))
                    {
                        if (cols > 0)
                        {
                            builder.Append("<td>" + count + " - " + number + "</td>");
                        }
                        else
                        {
                            builder.Append("</tr><tr><td>" + count + " - " + number + "</td>");
                            cols = 11;
                        }
                        count++;
                        number++;
                        cols--;
                    }
                    else
                        number++;
                }
                builder.Append("</table>");
                watch.Stop();
                var elapsedms = watch.ElapsedMilliseconds;
                double seconds = elapsedms / 1000;
                time = seconds.ToString();
                lbl_message.Text = builder.ToString();
                lbl_time.Text = time;
            }
        }
        else
            lbl_message.Text = "Please enter a numberic number.";

        lbl_time.Text = time;

        tb_number.Text = "";
        tb_number.Focus();
    }

Voici le code aspx.

<form id="form1" runat="server">
    <div>
        <p>Please enter a number: <asp:TextBox ID="tb_number" runat="server"></asp:TextBox></p>

        <p><asp:Button ID="btn_primeNumbers" runat="server" Text="Show Prime Numbers" OnClick="btn_primeNumbers_Click" />
        </p>
        <p><asp:Label ID="lbl_time" runat="server"></asp:Label></p>
        <p><asp:Label ID="lbl_message" runat="server"></asp:Label></p>
    </div>
</form>

Résultats: 10000 nombres premiers en moins d'une seconde

100000 nombres premiers en 63 secondes

Capture d'écran des 100 premiers nombres premiers enter image description here

0
riz

J'ai obtenu cela en lisant la première fois "Sieve of Atkin" sur Wikki plus une réflexion préalable que j'ai donnée à cela - je passe beaucoup de temps à coder à partir de zéro et je suis complètement à zéro sur les gens qui critiquent mon codage très dense, semblable à un compilateur style + Je n'ai même pas fait une première tentative pour exécuter le code ... la plupart des paradigmes que j'ai appris à utiliser sont ici, lisez et pleurez, obtenez ce que vous pouvez.

Soyez absolument et totalement sûr de vraiment tester tout cela avant toute utilisation, assurez-vous de ne le montrer à personne - c'est pour lire et considérer les idées. J'ai besoin de faire fonctionner l'outil de primalité, c'est donc là que je commence chaque fois que je dois faire fonctionner quelque chose.

Obtenez une compilation propre, puis commencez à supprimer ce qui est défectueux - j'ai près de 108 millions de frappes de code utilisable qui le font de cette façon, ... utilisez ce que vous pouvez.

Je travaillerai sur ma version demain.

package demo;
// This code is a discussion of an opinion in a technical forum.
// It's use as a basis for further work is not prohibited.
import Java.util.Arrays;
import Java.util.HashSet;
import Java.util.ArrayList;
import Java.security.GeneralSecurityException;

/**
 * May we start by ignores any numbers divisible by two, three, or five
 * and eliminate from algorithm 3, 5, 7, 11, 13, 17, 19 completely - as
 * these may be done by hand. Then, with some thought we can completely
 * prove to certainty that no number larger than square-root the number
 * can possibly be a candidate prime.
 */

public class PrimeGenerator<T>
{
    //
    Integer HOW_MANY;
    HashSet<Integer>hashSet=new HashSet<Integer>();
    static final Java.lang.String LINE_SEPARATOR
       =
       new Java.lang.String(Java.lang.System.getProperty("line.separator"));//
    //
    PrimeGenerator(Integer howMany) throws GeneralSecurityException
    {
        if(howMany.intValue() < 20)
        {
            throw new GeneralSecurityException("I'm insecure.");
        }
        else
        {
            this.HOW_MANY=howMany;
        }
    }
    // Let us then take from the rich literature readily 
    // available on primes and discount
    // time-wasters to the extent possible, utilizing the modulo operator to obtain some
    // faster operations.
    //
    // Numbers with modulo sixty remainder in these lists are known to be composite.
    //
    final HashSet<Integer> fillArray() throws GeneralSecurityException
    {
        // All numbers with modulo-sixty remainder in this list are not prime.
        int[]list1=new int[]{0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,
        32,34,36,38,40,42,44,46,48,50,52,54,56,58};        //
        for(int nextInt:list1)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list1");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are  are
        // divisible by three and not prime.
        int[]list2=new int[]{3,9,15,21,27,33,39,45,51,57};
        //
        for(int nextInt:list2)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list2");//
            }
        }
        // All numbers with modulo-sixty remainder in this list are
        // divisible by five and not prime. not prime.
        int[]list3=new int[]{5,25,35,55};
        //
        for(int nextInt:list3)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list3");//
            }
        }
        // All numbers with modulo-sixty remainder in
        // this list have a modulo-four remainder of 1.
        // What that means, I have neither clue nor guess - I got all this from
        int[]list4=new int[]{1,13,17,29,37,41,49,53};
        //
        for(int nextInt:list4)
        {
            if(hashSet.add(new Integer(nextInt)))
            {
                continue;
            }
            else
            {
                throw new GeneralSecurityException("list4");//
            }
        }
        Integer lowerBound=new Integer(19);// duh
        Double upperStartingPoint=new Double(Math.ceil(Math.sqrt(Integer.MAX_VALUE)));//
        int upperBound=upperStartingPoint.intValue();//
        HashSet<Integer> resultSet=new HashSet<Integer>();
        // use a loop.
        do
        {
            // One of those one liners, whole program here:
            int aModulo=upperBound % 60;
            if(this.hashSet.contains(new Integer(aModulo)))
            {
                continue;
            }
            else
            {
                resultSet.add(new Integer(aModulo));//
            }
        }
        while(--upperBound > 20);
        // this as an operator here is useful later in your work.
        return resultSet;
    }
    // Test harness ....
    public static void main(Java.lang.String[] args)
    {
        return;
    }
}
//eof
0
Nicholas Jordan

Pour connaître les 100 premiers nombres premiers, le code Java Java peut être pris en compte).

int num = 2;
int i, count;
int nPrimeCount = 0;
int primeCount = 0;

    do
    {

        for (i = 2; i <num; i++)
        {

             int n = num % i;

             if (n == 0) {

             nPrimeCount++;
         //  System.out.println(nPrimeCount + " " + "Non-Prime Number is: " + num);

             num++;
             break;

             }
       }

                if (i == num) {

                    primeCount++;

                    System.out.println(primeCount + " " + "Prime number is: " + num);
                    num++;
                }


     }while (primeCount<100);
0
Zakir Sajib