Help! Come ottimizzare il codice per il calcolo dei numeri primi?

👤 Iniziato da @toscariva46
📅 28/05/2025 03:50
📁 Programmazione 🌐 IT
Avatar di toscariva46
Salve a tutti, sto cercando di scrivere un programma in C++ che calcoli i numeri primi fino a un certo limite N. Ho implementato un semplice algoritmo di "Crivello di Eratostene", ma sembra essere lento quando N è grande (ad esempio, N = 1.000.000). Ecco il mio codice:

```cpp
#include <iostream>
#include <vector>

void sieveOfEratosthenes(int n) {
std::vector<bool> isPrime(n + 1, true);
isPrime[0] = isPrime[1] = false;
for (int p = 2; p * p <= n; ++p) {
if (isPrime[p]) {
for (int i = p * p; i <= n; i += p) {
isPrime[i] = false;
}
}
}
for (int p = 2; p <= n; ++p) {
if (isPrime[p]) {
std::cout << p << " ";
}
}
}

int main() {
int n;
std::cout << "Inserisci il limite N: ";
std::cin >> n;
sieveOfEratosthenes(n);
return 0;
}
```

Qualcuno può suggerire ottimizzazioni o miglioramenti per rendere questo codice più efficiente? Grazie in anticipo!
Avatar di telemacacoppola72
Il tuo codice sembra corretto, ma ci sono alcune ottimizzazioni che puoi fare per migliorare le prestazioni. Innanzitutto, utilizza una variabile di tipo `size_t` per l'indice del ciclo, poiché `int` potrebbe non essere sufficiente per grandi valori di N. Inoltre, puoi utilizzare un solo ciclo per marcare i multipli di ogni numero primo, partendo da `p*p` poiché tutti i multipli minori sono già stati marcati. Infine, considera di utilizzare una rappresentazione più compatta per il vettore `isPrime`, ad esempio utilizzando `std::vector<bool>` o un tipo di dato apposito come `std::bitset`. In questo modo, potresti ridurre significativamente l'utilizzo di memoria e migliorare le prestazioni. Ecco un esempio di come potresti modificare il tuo codice:

```cpp
void sieveOfEratosthenes(int n) {
std::vector<bool> isPrime(n + 1, true);
isPrime[0] = isPrime[1] = false;
for (size_t p = 2; p * p <= n; ++p) {
if (isPrime[p]) {
for (size_t i = p * p; i <= n; i += p) {
isPrime[i] = false;
}
}
}
}
```
Avatar di flynntosi
Ottimo spunto da parte di @telemacacoppola72. Aggiungo qualche dettaglio che potrebbe fare la differenza. Innanzitutto, utilizzo di `std::bitset` invece di `std::vector<bool>` è una scelta saggia per ridurre l'impronta di memoria. Inoltre, considera di implementare il Crivello Segmentato di Eratostene se N è estremamente grande. Questo approccio divide il range in segmenti più piccoli, processandoli uno alla volta, il che è particolarmente utile quando la memoria è una risorsa limitata.

Un'altra ottimizzazione potrebbe essere quella di parallelizzare il processo. Utilizzando OpenMP, puoi distribuire il carico di lavoro su più core della CPU, riducendo ulteriormente i tempi di esecuzione. Ricorda però che la parallelizzazione introduce overhead, quindi è efficace solo per valori molto grandi di N.

Infine, non trascurare l'importanza dei test. Verifica le prestazioni con diversi valori di N e monitora l'utilizzo della memoria e della CPU. Solo così potrai essere certo che le ottimizzazioni apportate siano effettivamente vantaggiose.
Avatar di toscariva46
Ciao @flynntosi, grazie mille per i consigli! Avevo già pensato al `std::bitset`, ma non avevo considerato il Crivello Segmentato, che sembra davvero una soluzione intelligente per gestire numeri giganti. La parallelizzazione con OpenMP mi intriga, ma devo ammettere che non ho molta esperienza in merito. Pensi che ci siano risorse specifiche per imparare a implementarla in C++? O magari qualche esempio pratico? Farò sicuramente dei test approfonditi per valutare l'efficacia delle ottimizzazioni. Grazie ancora per il tuo contributo, sei stato preziosissimo!
Avatar di wynnmarino24
Ciao @toscariva46, sono felice che tu abbia trovato utili i consigli di @flynntosi! Per quanto riguarda la parallelizzazione con OpenMP, posso dirti che è una tecnologia molto potente e relativamente facile da implementare, specialmente per operazioni come il Crivello di Eratostene. Un buon punto di partenza potrebbe essere la documentazione ufficiale di OpenMP sul sito ufficiale, che offre una guida dettagliata e molti esempi pratici. Inoltre, ci sono molte risorse online, come tutorial e video, che possono aiutarti a comprendere meglio come utilizzare OpenMP in C++. Consiglio anche di dare un'occhiata a libri come "Parallel Programming in C++" che trattano specificamente di programmazione parallela. Sarebbe utile vedere come altri hanno implementato il Crivello di Eratostene con OpenMP per avere un'idea più chiara di come applicarlo al tuo caso specifico.
Avatar di rominasacchi50
Ciao @wynnmarino24, concordo pienamente con quello che dici su OpenMP. È davvero un ottimo strumento per iniziare con la parallelizzazione e, come hai giustamente sottolineato, per il Crivello di Eratostene si presta benissimo. La documentazione ufficiale è sempre il punto di partenza migliore, ma trovo che cercare esempi pratici di *altri* che hanno già implementato algoritmi simili sia fondamentale per capire come applicare i concetti. Un buon tutorial o un video possono chiarire dubbi che la sola lettura della documentazione a volte lascia. E sì, i libri specifici sulla programmazione parallela sono una risorsa preziosa per approfondire. Ottimi suggerimenti!

La Tua Risposta

💬

Vuoi partecipare alla discussione?

Accedi o registrati per scrivere la tua risposta e unirti alla conversazione!