75 votes

C - déterminer si un nombre est premier

J'essaie de trouver une méthode qui prend un entier et renvoie un booléen pour dire si le nombre est premier ou non et je ne connais pas grand-chose au C ; quelqu'un pourrait-il me donner quelques conseils ?

En gros, je ferais cela en C# comme ceci :

static bool IsPrime(int number)
{
    for (int i = 2; i < number; i++)
    {
        if (number % i == 0 && i != number)
            return false;
    }
    return true;
}

1 votes

Il s'agit davantage d'une question de mathématiques que de programmation, n'est-ce pas ?

51 votes

Voici quelques pointeurs : int *ptr ; int *ptr2 ; int *ptr3. Désolé, je n'ai pas pu m'en empêcher. Quelle est la taille des nombres que vous allez vérifier ? Et aussi, voulez-vous une heuristique ou quelque chose qui fonctionne toujours ?

3 votes

Présentez votre algorithme (de la manière dont vous le testez sans code) et ensuite nous pourrons peut-être vous aider à l'exprimer en C.

154voto

Stephen Canon Points 58003

OK, oubliez C. Supposons que je vous donne un nombre et que je vous demande de déterminer s'il est premier. Comment vous y prenez-vous ? Écrivez clairement les étapes, puis se soucier de les traduire en code.

Une fois l'algorithme déterminé, il sera beaucoup plus facile pour vous de trouver comment écrire un programme, et pour les autres de vous aider.

éditer : Voici le code C# que vous avez posté :

static bool IsPrime(int number) {
    for (int i = 2; i < number; i++) {
        if (number % i == 0 && i != number) return false;
    }
    return true;
}

C'est très près C valide tel quel ; il n'y a pas de bool en C, et aucun true ou false Il faut donc le modifier un peu (edit : Kristopher Johnson signale correctement que C99 a ajouté l'en-tête stdbool.h). Puisque certaines personnes n'ont pas accès à un environnement C99 (mais vous devriez en utiliser un !), faisons ce changement très mineur :

int IsPrime(int number) {
    int i;
    for (i=2; i<number; i++) {
        if (number % i == 0 && i != number) return 0;
    }
    return 1;
}

C'est un programme C parfaitement valide qui fait ce que vous voulez. Nous pouvons l'améliorer un peu sans trop d'effort. Tout d'abord, notez que i est toujours inférieur à number donc la vérification que i != number réussit toujours ; on peut s'en débarrasser.

De plus, vous n'avez pas besoin d'essayer des diviseurs jusqu'à number - 1 ; vous pouvez arrêter de vérifier lorsque vous atteignez sqrt(nombre). Depuis sqrt est une opération à virgule flottante et cela apporte tout un tas de subtilités, nous ne calculerons pas réellement sqrt(number) . Au lieu de cela, nous pouvons simplement vérifier que i*i <= number :

int IsPrime(int number) {
    int i;
    for (i=2; i*i<=number; i++) {
        if (number % i == 0) return 0;
    }
    return 1;
}

Une dernière chose, cependant : il y avait un petit bug dans votre algorithme original ! Si number est négatif, ou zéro, ou un, cette fonction affirmera que le nombre est premier. Vous voudrez probablement gérer cela correctement, et vous voudrez peut-être faire en sorte que la fonction number sont non signées, car il est plus probable que vous ne vous souciiez que des valeurs positives :

int IsPrime(unsigned int number) {
    if (number <= 1) return 0; // zero and one are not prime
    unsigned int i;
    for (i=2; i*i<=number; i++) {
        if (number % i == 0) return 0;
    }
    return 1;
}

Ce n'est certainement pas la façon la plus rapide de vérifier si un nombre est premier, mais cela fonctionne, et c'est assez simple. Nous avons à peine eu à modifier votre code !

12 votes

Pour info, la norme C99 définit un en-tête <stdbool.h> qui fournit bool , true et false .

0 votes

J'ai aussi oublié de mentionner que je n'ai pas besoin de me préoccuper des 0, 1 ou des négatifs, il s'agit juste de parcourir une liste de 50 nombres si je me souviens bien, mais merci encore.

0 votes

@Kristopher : merci, j'avais oublié celui-là. @Jimmy : content d'aider, heureux que ce ne soit qu'un bug de documentation =)

29voto

monksy Points 8788

Je suis surpris que personne ne l'ait mentionné.

Utilisez le Le tamis d'Eratosthène

Détails :

  1. Fondamentalement, les nombres non primaires sont divisibles par un autre nombre que 1 et eux-mêmes.
  2. Par conséquent : un nombre non primaire sera un produit de nombres premiers.

Le tamis d'Eratosthène trouve un nombre premier et le stocke. Lorsqu'on vérifie la primarité d'un nouveau nombre, tous les nombres premiers précédents sont comparés à la liste des nombres premiers connus.

Raisons :

  1. Cet algorithme/problème est connu sous le nom de " Un parallèle embarrassant "
  2. Il crée une collection de nombres premiers
  3. C'est un exemple de problème de programmation dynamique
  4. C'est rapide !

9 votes

C'est aussi O(n) dans l'espace, et tant que votre calcul ne porte que sur une seule valeur, c'est un énorme gaspillage d'espace sans gain de performance.

3 votes

(En fait O(n log n) ou plus si vous prenez en charge un grand nombre de personnes...)

2 votes

Qui ne calcule qu'une seule valeur pour une prime pendant toute la durée de vie de l'application ? Les nombres premiers sont un bon candidat pour être mis en cache.

10voto

Eric Bainville Points 5300
  1. Construisez une table de petits nombres premiers, et vérifiez s'ils divisent votre nombre d'entrée.
  2. Si le nombre a survécu à 1, essayez les tests de pseudo primalité avec une base croissante. Voir Test de primauté de Miller-Rabin par exemple.
  3. Si votre nombre survient à 2, vous pouvez conclure qu'il est premier s'il est inférieur à certaines limites bien connues. Sinon, votre réponse sera seulement "probablement premier". Vous trouverez quelques valeurs pour ces limites dans la page wiki.

3 votes

+1 : complètement exagéré par rapport à la question posée, mais néanmoins correct.

0 votes

Notez que Guy L. a récemment suggéré d'utiliser Miller-Rabin dans un réponse également, et lié à rosettacode.org/wiki/Miller-Rabin_primality_test#C - qui montre une implémentation en C utilisant BPF . Cette entrée comporte également un certain nombre d'implémentations dans une grande variété d'autres langages.

3voto

Matt Lacey Points 50756

Vérifiez le module de chaque nombre entier de 2 jusqu'à la racine du nombre que vous vérifiez.

Si le module est égal à zéro, alors il n'est pas premier.

pseudo-code :

bool IsPrime(int target)
{
  for (i = 2; i <= root(target); i++)
  {
    if ((target mod i) == 0)
    {
      return false;
    }
  }

  return true;
}

2 votes

Bien sûr, l'inconvénient est que le sqrt est calculé à chaque itération, ce qui le ralentit considérablement.

9 votes

Tout compilateur raisonnable devrait être capable de détecter que Root(target) est un invariant de boucle et de le hisser.

1 votes

(et si vous avez un compilateur qui ne peut pas faire cette optimisation, vous devriez absolument déposer un bogue pour faire savoir à l'auteur du compilateur qu'il manque cette optimisation).

2voto

J'ajouterais simplement qu'aucun nombre pair (barre 2) ne peut être un nombre premier. Cela entraîne une autre condition avant la boucle for. Ainsi, le code final devrait ressembler à ceci :

int IsPrime(unsigned int number) {
    if (number <= 1) return 0; // zero and one are not prime
    if ((number > 2) && ((number % 2) == 0)) return 0; //no even number is prime number (bar 2)
    unsigned int i;
    for (i=2; i*i<=number; i++) {
        if (number % i == 0) return 0;
    }
    return 1;
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X