Didaxis
lecție · Informatică

Ciurul lui Eratostene

Ciurul lui Eratostene este un algoritm care găsește toate numerele prime până la o limită N: pornești cu toate numerele de la 2 la N nemarcate și, pentru fiecare număr rămas nemarcat, îi marchezi multiplii ca fiind compuși. Numerele care rămân nemarcate sunt prime. Pentru un singur număr, e suficient testul cu divizori până la rădăcina lui pătrată.

Se face în:
Clasa a IX-a
Actualizat la: 30 octombrie 2026
1pe scurtstratul 1 din 2 · rezumatul lecției

Pe scurt

Ciurul lui Eratostene află toate numerele prime până la o limită dată. Pornim cu numerele de la 2 la și eliminăm multiplii fiecărui număr rămas. Pentru , eliminăm 4, 6, 8, 10 ca multipli de 2, apoi 9 ca multiplu de 3; rămân 2, 3, 5, 7.

Desen la lecția „Ciurul lui Eratostene”
2în detaliustratul 2 din 2 · pentru clasă și Bacalaureat

În detaliu

Ciurul lui Eratostene construiește, pentru o limită dată, un tablou de valori logice prim[0..N]: prim[i] este adevărat dacă este număr prim. Tabloul pornește cu toate valorile adevărate, apoi se marchează 0 și 1 ca neprime. Pentru fiecare rămas marcat prim și cu se marchează ca neprime multiplii lui , începând cu : multiplii mai mici de forma , cu , au fost deja marcați când s-a prelucrat un factor prim al lui . Prelucrarea se oprește la , pentru că orice număr compus are un divizor prim cel mult . Timpul este proporțional cu , iar memoria este proporțională cu .

Exemplul 1 — numerele prime până la 30. Se prelucrează valorile cu , adică 2, 3 și 5.

  1. : se marchează 4, 6, 8, ..., 30, în total 14 numere.
  2. : se marchează 9, 12, 15, ..., 30, în total 8 numere, dintre care 12, 18, 24 și 30 fuseseră marcate de 2.
  3. este deja marcat și se sare peste el.
  4. : se marchează 25 și 30, în total 2 numere; 30 era deja marcat.
  5. are , deci prelucrarea se oprește.

Rămân nemarcate 2, 3, 5, 7, 11, 13, 17, 19, 23 și 29: zece numere prime. În total s-au făcut de marcări pentru cele 19 numere compuse de până la 30, deci cinci marcări au căzut pe numere deja marcate.

N = 30
prim = [True] * (N + 1)
prim[0] = prim[1] = False
p = 2
while p * p <= N:
    if prim[p]:
        for m in range(p * p, N + 1, p):
            prim[m] = False
    p += 1
print([i for i in range(2, N + 1) if prim[i]])

Exemplul 2 — numărul și cel mai mare număr prim până la 100. Aceeași metodă, scrisă în C++, numără valorile rămase adevărate:

#include <iostream>
using namespace std;
int main() {
    const int N = 100;
    bool prim[N + 1];
    for (int i = 0; i <= N; ++i) prim[i] = true;
    prim[0] = prim[1] = false;
    for (int p = 2; p * p <= N; ++p)
        if (prim[p])
            for (int m = p * p; m <= N; m += p)
                prim[m] = false;
    int nr = 0, ultim = 0;
    for (int i = 2; i <= N; ++i)
        if (prim[i]) { nr++; ultim = i; }
    cout << nr << ' ' << ultim;
    return 0;
}

Programul afișează 25 97: între 1 și 100 sunt 25 de numere prime, iar cel mai mare este 97. După construirea ciurului, întrebarea „este prim?” se rezolvă printr-o singură citire din tablou, în timp constant, ceea ce îl face potrivit atunci când trebuie testate multe numere de la 1 la .

Ideea ciurului. Scrii numerele de la 2 la . Primul număr nemarcat, 2, e prim; îi marchezi toți multiplii mai mari. Următorul nemarcat, 3, e prim; îi marchezi multiplii. Continui așa: fiecare număr care a rămas nemarcat până când ajungi la el nu are niciun divizor prim mai mic decât el, deci este prim. Bucla exterioară se oprește la , pentru că dacă numărul nu mai are multipli de marcat.

Testul pentru un singur număr. Un număr natural este prim dacă are exact doi divizori, pe 1 și pe . Deci 0 și 1 nu sunt prime, iar 2 este singurul număr prim par. Încerci divizorii cât timp ; dacă găsești unul, nu e prim. În cod, condiția se scrie d <= n / d: evită calculul radicalului și erorile de rotunjire ale lui sqrt, iar pentru apropiat de valoarea maximă a tipului int (2147483647) nu calculează produsul d * d, care ar putea depăși tipul. Pentru numere întregi pozitive, cele două condiții sunt echivalente.

int prim(int n) {
    if (n < 2)
        return 0;
    for (int d = 2; d <= n / d; d++)
        if (n % d == 0)
            return 0;
    return 1;
}

Pentru 997 se încearcă divizorii de la 2 la 31 () și niciunul nu se potrivește: 997 este prim. Pentru , testul se oprește la .

În varianta C++ cu tablou c, convenția este: c[k] = 0 înseamnă „ este prim”, c[k] = 1 înseamnă „ nu este prim”, iar c[0] = c[1] = 1. Pentru fiecare cu și c[i] == 0, marchezi c[j] = 1 pentru , până la .

Cât de rapid este. Pentru , ciurul face 2 122 048 de marcări, iar după aceea răspunsul la întrebarea „ este prim?” este o singură citire, c[k]. Numărul de marcări crește aproape proporțional cu (ordinul ). Testarea separată a fiecărui număr până la cu divizori până la poate cere, în cel mai rău caz, de ordinul împărțiri. Prețul ciurului este memoria: un tablou cu elemente, care pentru înseamnă aproximativ un megaoctet dacă elementele sunt de tip char sau bool.

Exemple suplimentare

Exemplul 3 — urmărirea pentru și cazuri-limită. Se prelucrează , pentru că , iar . Numărul de marcări este 49 pentru (de la 4 la 100), 31 pentru (de la 9 la 99), 16 pentru (de la 25 la 100) și 8 pentru (de la 49 la 98): în total marcări. Doar 74 dintre ele cad pe numere încă nemarcate, deoarece între 2 și 100 sunt de numere compuse; restul sunt remarcări. Pentru , marcarea începe de la 49, nu de la 14: numerele 14, 21, 28, 35 și 42 sunt multipli ai lui 2, 3 sau 5, deci au fost marcate mai devreme. Pentru ciclul exterior nu se execută deloc (), iar rezultatul corect este singurul prim 2. Pentru nu rămâne niciun prim.

Exemple rezolvate

Exemplul 1: ciurul până la 30, pas cu pas.

  1. (nemarcat, prim): marchezi 4, 6, 8, …, 30.
  2. (nemarcat, prim): marchezi 9, 12, 15, 18, 21, 24, 27, 30; unele erau deja marcate.
  3. este marcat, deci nu faci nimic.
  4. (nemarcat, prim): marchezi 25 și 30.
  5. : , bucla se oprește.
  6. Rămân nemarcate: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, adică 10 numere prime.
#include <iostream>
using namespace std;

char c[31];

int main() {
    int N = 30;
    c[0] = c[1] = 1;
    for (int i = 2; i * i <= N; i++)
        if (c[i] == 0)
            for (int j = i * i; j <= N; j = j + i)
                c[j] = 1;                // j are divizorul i, deci nu e prim
    for (int k = 2; k <= N; k++)
        if (c[k] == 0)
            cout << k << " ";
    cout << "\n";
    return 0;
}

Programul afișează:

2 3 5 7 11 13 17 19 23 29

Tabloul c este global, deci toate elementele lui pornesc de la 0.

Exemplul 2: câte numere prime sunt până la . Se citește . Afișează câte numere prime sunt cel mult egale cu .

#include <iostream>
using namespace std;

char c[1000001];

int main() {
    int N;
    cin >> N;
    c[0] = c[1] = 1;
    for (int i = 2; i * i <= N; i++)
        if (c[i] == 0)
            for (int j = i * i; j <= N; j = j + i)
                c[j] = 1;
    int nr = 0;
    for (int k = 2; k <= N; k++)
        if (c[k] == 0)
            nr++;
    cout << nr << "\n";
    return 0;
}

Pentru intrarea 1000000, programul afișează:

78498

Pentru 100 afișează 25, iar pentru 30 afișează 10, ca în exemplul 1.

Exemplul 3: un singur număr. Verifică dacă 997 și 1001 sunt prime, cu subprogramul prim de mai sus.

  1. 997: niciun divizor de la 2 la 31, deci este prim.
  2. 1001: se împarte la 7, deci nu este prim. Pentru un singur număr nu are rost să construiești ciurul până la 1001.
#include <iostream>
using namespace std;

int prim(int n) {
    if (n < 2)
        return 0;
    for (int d = 2; d <= n / d; d++)
        if (n % d == 0)
            return 0;
    return 1;
}

int main() {
    int n;
    cin >> n;
    cout << prim(n) << "\n";
    return 0;
}

Pentru intrarea 997, programul afișează:

1

Pentru 1001 afișează 0.

Exemplul 4: numere prime gemene. Două numere prime gemene sunt două numere prime care diferă prin 2, de exemplu 11 și 13. Câte perechi de numere prime gemene au ambele numere cel mult egale cu 100?

  1. Construiești ciurul până la 100.
  2. Pentru fiecare de la 2 la 98, verifici dacă c[p] == 0 și c[p + 2] == 0.
  3. Perechile sunt (3, 5), (5, 7), (11, 13), (17, 19), (29, 31), (41, 43), (59, 61), (71, 73): 8 perechi.
#include <iostream>
using namespace std;

char c[101];

int main() {
    int N = 100, nr = 0;
    c[0] = c[1] = 1;
    for (int i = 2; i * i <= N; i++)
        if (c[i] == 0)
            for (int j = i * i; j <= N; j = j + i)
                c[j] = 1;
    for (int p = 2; p + 2 <= N; p++)
        if (c[p] == 0 && c[p + 2] == 0) {
            cout << "(" << p << "," << p + 2 << ") ";
            nr++;
        }
    cout << "\n" << nr << "\n";
    return 0;
}

Programul afișează:

(3,5) (5,7) (11,13) (17,19) (29,31) (41,43) (59,61) (71,73)
8

Exemplul 5: nivel de examen, multe întrebări. Se citesc și apoi numere naturale, fiecare cel mult 1 000 000. Afișează câte dintre ele sunt prime, cu un algoritm eficient din punctul de vedere al timpului de executare.

  1. Construiești o singură dată ciurul până la 1 000 000.
  2. Pentru fiecare număr citit, răspunsul este c[x] == 0, o singură operație, oricât de mare ar fi .
  3. Pentru numerele 2, 15, 97, 1, 999983, 1000000 răspunsul este 3: 2, 97 și 999983 (cel mai mare număr prim mai mic decât un milion).
#include <iostream>
using namespace std;

char c[1000001];

int main() {
    const int N = 1000000;
    c[0] = c[1] = 1;
    for (int i = 2; i * i <= N; i++)
        if (c[i] == 0)
            for (int j = i * i; j <= N; j = j + i)
                c[j] = 1;
    int n, x, nr = 0;
    cin >> n;
    for (int k = 1; k <= n; k++) {
        cin >> x;
        if (c[x] == 0)
            nr++;
    }
    cout << nr << "\n";
    return 0;
}

Pentru intrarea 6 urmată de 2 15 97 1 999983 1000000, programul afișează:

3

Dacă ai testa fiecare număr cu divizori până la , ai face până la 1 000 de împărțiri pentru fiecare număr citit; cu ciurul, timpul de după construcție nu mai depinde de mărimea numerelor.

Unde apare la examen

La Bacalaureatul la informatică, matematică-informatică, programa de examen cuprinde „Divizibilitate. Numere prime. Algoritmul lui Euclid”, la algoritmii elementari, și „Analiza complexității unui algoritm”; ciurul lui Eratostene nu este numit, dar este metoda obișnuită când se cere un algoritm eficient pentru multe numere până la aceeași limită (anexa 2 la OMECTS 4800/2010). Formatul probei și subiectele din 2026 sunt pe pagina subiectelor și baremelor Bac 2026.

Testarea primalității este la clasa a IX-a pe programa veche (OMECI 5099/2009), iar tablourile, de care are nevoie ciurul, la clasa a X-a. Pe programa nouă de clasa a IX-a apar parcurgerea divizorilor, descompunerea în factori primi și listele (OMEC 6930/2025, anexa 42).

Greșeli frecvente

  • Greșit: 0 și 1 rămân marcate ca prime.
    Corect: ambele se marchează neprime la început; în ciur, c[0] și c[1] se marchează separat, iar testul începe cu if (n < 2) return 0;.
  • Greșit: se șterge și p când procesăm multiplii lui p.
    Corect: marcarea începe de la (sau de la ), niciodată de la ; altfel toate numerele prime ar fi marcate ca neprime.
  • Greșit: după ciur trebuie retestat fiecare număr prin împărțiri.
    Corect: marcajele conțin deja răspunsul pentru interval.
  • Greșit: condiția testului este d * d < n.
    Corect: cu d * d < n, pătratele de numere prime, ca 49, ar fi declarate prime; condiția corectă include egalitatea.
  • Greșit: pentru un tablou cu 1 000 000 de elemente este suficient.
    Corect: tabloul are nevoie de 1 000 001 elemente, ca să existe c[1000000].
  • Greșit: un tablou de un milion de elemente poate fi declarat local în main.
    Corect: poate depăși memoria rezervată variabilelor locale; declarat global, ca în exemple, este și inițializat automat cu 0.
în contul tăuPremium

Testează-te pe această lecție

Lecția o citești aici, fără cont. Testele pe lecții și capitole sunt în cont, cu grile originale Didaxis și explicația fiecăreia: gratuit 10 grile pe zi, fără limită cu Premium, 49 de lei pe lună pentru fiecare copil.

Înainte și după

Întrebări frecvente

De ce caut divizori doar până la radical din n?
Divizorii vin în perechi: dacă d divide n, atunci și n / d divide n, iar unul dintre ei este cel mult √n. Dacă n nu are niciun divizor între 2 și √n, nu are nici mai mari decât √n, deci este prim.
Când folosesc ciurul și când testul de primalitate?
Pentru un singur număr sau pentru câteva, testul cu divizori până la √n. Când trebuie să știi, pentru multe numere până la aceeași limită, dacă sunt prime, construiești o dată ciurul și răspunzi apoi fiecărei întrebări cu o singură citire din tablou.
Câte numere prime sunt mai mici decât 100?
25: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89 și 97.

Surse și referințe

Redactare proprie, conform programei:

  • OMEC 4370/2026, anexa 8, Informatică IX intensiv, p. 155–156
  • OMEC 6930/2025, anexa 66, Informatică IX CS militar, Monitorul Oficial nr. 4 bis/8.01.2026, pp. 2563–2578; cdn.edupedu.ro; centralizator oficial actualizat prin OMEC 3224/2026, legislatie.just.ro

Documente consultate

  • Programa școlară de informatică, clasa a IX-a (OMECI 5099/2009, anexa 5), CNCE; rocnee.eu
  • Programa școlară de informatică, clasa a IX-a, matematică-informatică (OMEC 6930/2025, anexa 42), p. 1653–1654; rocnee.eu
  • Programa școlară de informatică, clasa a X-a (OMECI 5099/2009, anexa 5), CNCE; rocnee.eu
  • Programa de bacalaureat la informatică, matematică-informatică (anexa 2 la OMECTS 4800/2010), Ministerul Educației; edu.ro

Desene: Redactare proprie (desen original)

lecțiile sunt gratuite

Ai citit lecția. Acum verifică-te.