Nombres premiers C++
Résolu/Fermé
A voir également:
- Nombre premier en c
- Dans cette présentation, trouvez l'étoile. quel nombre contient-elle ? ✓ - Forum Word
- En raison d'un nombre important d'échec de connexion snapchat - Forum Snapchat
- Nombre facile - Télécharger - Outils professionnels
- Premier pro - Télécharger - Montage & Édition
- Dans la présentation, sans modifier leur position dans la feuille : passez le rectangle noir en arrière-plan ; passez le rectangle bleu au premier plan ; passez le rectangle hachuré au premier plan. quel mot apparaît ? ✓ - Forum LibreOffice / OpenOffice
1 réponse
SypayV
Messages postés
6583
Date d'inscription
vendredi 28 décembre 2007
Statut
Contributeur
Dernière intervention
19 février 2023
449
30 janv. 2016 à 08:29
30 janv. 2016 à 08:29
Bonjour,
Je ne connais pas la méthode de Dana Jacobsen, mais en général ces méthodes sont approximatives (ça l'est encore plus avec un ordinateur, car un ordinateur ne sait pas compter en nombre réel).
En ce qui concerne votre algorithme, plusieurs choses :
- Vous testez les nombres pairs. Les nombres pairs sont toujours non-premiers car ils sont tous divisibles par 2.
- Votre boucle va re-calculer la racine carrée de n à chaque fois.
- Vous utilisez cout dans la boucle. C'est l'opération la plus lente du programme.
- Vous n'utilisez pas l'opérateur de reste de division entière (%).
- Et vous n'utilisez qu'un seul cœur de votre processeur.
Voici le code que je vous propose, il utilise le c++11 et vient à bout de 20000 nombres en 0 seconde (2500 µs) sur une machine n'ayant qu'un processeur.
Imaginez si vous l'utilisez sur votre machine multi-processeurs ...
Vous pouvez le tester sur ce site : http://cpp.sh/5vfw
Je ne connais pas la méthode de Dana Jacobsen, mais en général ces méthodes sont approximatives (ça l'est encore plus avec un ordinateur, car un ordinateur ne sait pas compter en nombre réel).
En ce qui concerne votre algorithme, plusieurs choses :
- Vous testez les nombres pairs. Les nombres pairs sont toujours non-premiers car ils sont tous divisibles par 2.
- Votre boucle va re-calculer la racine carrée de n à chaque fois.
- Vous utilisez cout dans la boucle. C'est l'opération la plus lente du programme.
- Vous n'utilisez pas l'opérateur de reste de division entière (%).
- Et vous n'utilisez qu'un seul cœur de votre processeur.
Voici le code que je vous propose, il utilise le c++11 et vient à bout de 20000 nombres en 0 seconde (2500 µs) sur une machine n'ayant qu'un processeur.
Imaginez si vous l'utilisez sur votre machine multi-processeurs ...
Vous pouvez le tester sur ce site : http://cpp.sh/5vfw
#include <iostream> // cout, cin #include <cmath> // floor, sqrt #include <thread> // thread, hardware_concurrency #include <atomic> // atomic #include <vector> // vector #include <chrono> // steady_clock typedef unsigned int base_int; using namespace std; inline bool IsOdd(base_int const n) // Répond vrai si n est impair { return (n & 1) == 1; } inline bool IsPrime(base_int const n) // Répond vrai si n est premier { base_int const fs = floor(sqrt(n)); // Vaut mieux éviter de le re-calculer à chaque fois for(base_int k = 2; k <= fs; ++k) if(n % k == 0) return false; // % est l'opérateur qui donne le reste de la divison entière. Si le reste est 0, alors n est divisible par k donc n n'est pas premier. return true; } int main() { atomic<base_int> thread_count(thread::hardware_concurrency()); atomic<base_int> prime_count(0); base_int n; /* Chaque thread va s'occuper de tester des nombres uniquement impairs. On a donc besoin d'un nombre de threads pair, voir la suite. */ if(IsOdd(thread_count)) --thread_count; if(thread_count == 0) thread_count = 2; // On sera un peu plus lent sur les monoprocesseurs ... tant pis. vector<thread> thread_pool; thread_pool.reserve(thread_count); cout << "Jusqu'a quel nombre voulez vous afficher les nombres premiers ?" << endl; cin >> n; chrono::steady_clock::time_point tp_start = chrono::steady_clock::now(); if(n > 1) { cout << "2" << endl; ++prime_count; for(base_int start = 3, t = 0; t < thread_count; start += 2, ++t) { thread_pool.push_back( thread([=, &thread_count, &prime_count]() { for( base_int a = start; // On commence sur un nombre impair a <= n; a += thread_count /* On reste sur des nombres impairs car les nombres pairs sont divisibles par 2 et sont donc toujours premiers. thread_count est pair. */ ) { if(IsPrime(a)) { ++prime_count; //cout << n << endl; // Attention : cout est une opération blocante et afficher du text pendant l'opération va sérieusement ralentir le programme. De plus, on utilise des threads et celà va mélanger tout le texte. } } } ) ); } } for(thread & n : thread_pool) n.join(); thread_pool.clear(); chrono::steady_clock::time_point tp_end = chrono::steady_clock::now(); cout << "Parmi les " << n << " premiers nombre, " << prime_count << " sont premiers (Resultat donne avec " << thread_count << " threads pour " << thread::hardware_concurrency() << " processeurs logiques en " << chrono::duration_cast<chrono::microseconds>(tp_end - tp_start).count() << " microsecondes, soit " << chrono::duration_cast<chrono::seconds>(tp_end - tp_start).count() << " secondes)." << endl; // pause int p; cin >> p; return 0; }
30 janv. 2016 à 18:34
Merci beaucoup pour tout cela, j'ai quand meme quelques questions...
Code::Blocks ne prend pas en charge les fonctionnalites C++11 ?
De plus, sur C++Shell, le programme ne m'affiche pas tous les nombres, seulement un "2" quand je rentre 20000 par exemple...
Mais sinon, j'ai a peu pres compris le code, meme s'il y a beaucoup de fonctions que je ne connais pas... Merci encore.
EchoIsON.
Modifié par SypayV le 30/01/2016 à 20:50
Voici comment l'activer : https://stackoverflow.com/questions/18174988/how-can-i-add-c11-support-to-codeblocks-compiler/24398366#24398366
J'ai commenté la partie du code qui affiche les nombres car si on l'active alors le programme va ralentir et le texte sera désordonné car le code est parallèle.
Exemple : http://cpp.sh/673b4
Il faut créer un autre thread qui devra s'occuper d'afficher le texte.
Mais il sera rapidement dépassé, c'est à dire que les calculs seront finis avant même qu'il ait fini d'afficher tout le texte ... donc la meilleure solution est d'enregistrer les nombres et de les afficher à la fin du programme.
Exemple : http://cpp.sh/52gt
Cependant, le voilà déjà 2 fois moins rapide.
Le 2 est affiché à l'avance car sinon ce serait la misère avec les threads, pour leur dire de compter uniquement des impairs. Il y a un thread qui commence à 3, l'autre commence à 5, l'autre commence à 7, ainsi de suite ... Et ensuite ils passent respectivement à 3+nombre_de_theads, 5+nombre_de_theads, etc ... Chaque thread à sa propre échelle de nombre à calculer, nombre_de_threads étant toujours pair : pair+impair=impair.
Si tu veux en apprendre plus sur le code fourni, cherches avec google sur :
Multithread, opérations atomiques, c++11 fonctions lambda et pour le reste vois avec la documentation https://fr.cppreference.com/w/cpp
Edit : Je viens de me rendre compte que j'ai fait une erreur.
Pour que chaque thread ait sa propre échelle, il faut incrémenter de 2*nombre_de_threads ...et pas seulement une fois;
http://cpp.sh/25sp
Voilà, on est devenu 2 fois plus rapide sur le site. Ce sera encore 4 fois plus rapide que ça sur un quad core.