IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C++ Discussion :

Crible d'Eratosthène segmenté


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 69
    Par défaut Crible d'Eratosthène segmenté
    Bonjour à tous,

    J'aimerais coder l'algorithme du crible segmenté en c++. J'ai déjà bien exploré le crible normal, et les performances en hausse de la version segmentée m'attirent.

    Du coup j'ai écris le code suivant, qui est une version très naïve du crible, je veux juste que ça fonctionne et pouvoir après l'optimiser.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     
    #include <iostream>
    #include <math.h>
    #include <vector>
    #include <cstdlib>
     
    using namespace std;
     
    int main()
    {
    int max = 100000;
    int square, i, j,k;
    int limite = ceil(sqrt(max));
    int compteur2 = 0;
    int slice;
     
    if(max > 10000)
    slice = 10000;
    else
    slice = limite;
     
    if(limite % 2 != 0)
    limite++;
     
    square = ceil(sqrt(limite));
     
    vector<char> tableau(limite, 0x1);
     
    for(i = 2; i < limite; i+=2)
    {
        tableau[i] = 0x0;
    }
     
    for(j = 3; j <= square; j+=2)
    {
        for(k = j * j; k <= limite; k+= j)
        {
            tableau[k] = 0x0;
        }
    }
     
    int compteur = 1;
     
    for(i = 3; i < limite; i+=2)
    {
        if(tableau[i] == 0x1)
        compteur++;
    }
     
    std::vector<int> segment(slice,1);
     
    for(int y = limite; y <= max;y+=slice)
    {
        for(int z = 0; z <= slice; z++)
        {
            if(z % 2 == 0)
            segment[z] = 0;
            else
            {
                if(z+y < max)
                segment[z] = z + y;
                else
                segment[z] = 0;
            }
        }
     
        for(int g = 3; g <= limite; g+=2)
        {
            if(tableau[g] == 0x1)
            {
                for(int h = 1;h <= slice;h++)
                {
     
                if(segment[h] != 0)
                {
                    if(segment[h] % g == 0)
                    segment[h] = 0;
                }
     
     
                }
            }
        }
        for(int r = 1; r <= slice;r++)
        {
            if(segment[r] != 0)
            {
                compteur2++;
     
            }
        }
     
    }
     
    cout << compteur2+compteur << endl;
     
    return 0;
    }
    Bon je sais, le code est sale mais j'ai essayé tellement de choses que forcément ça salit

    Du coup mon problème est le suivant : Si je déclare max à plus de 100.000, le programme plante au moment de la déclaration du vector<int> segment. Ce que je ne comprend pas, étant donné que je l'initialise avec la variable "slice" qui n'a rien à voir avec "max".

    Si je remplace ce vector par un array de int, ça marche très bien.

    Autre problème, et c'est peut-être lié, si vous lisez le code vous remarquerez ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    if(z+y < max)
    segment[z] = z + y;
    else
    segment[z] = 0;
    C'est la seule solution que j'ai trouvé à un problème, en effet z va de limite à max par pas de slice, à la fin je me retrouve donc avec un vector segment qui fait toujours la même taille (ici 10.000), alors que je n'ai besoin que d'une taille de 10.000 - limite. Je ne sais pas si je me fais bien comprend

    Du coup, est-il possible "proprement" de fixer la taille du vector<int> segment dans ma boucle z ?

    Autre question, niveau performance, que vaut-il mieux choisir entre un vector et un array, sachant que je compte déclarer des array/vector de unsigned long long (64 bits donc) d'une taille comprise entre 32k et 256k selon le choix de l'utilisateur ?

    Merci pour vos éclaircissements

  2. #2
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    Bonjour,

    quel compilateur utilises-tu?

    Essaie de remplacer
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> segment(slice,1);
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    std::vector<int> segment(slice);
    , et dis-nous ce que ça donne.

    De façon générale, les tableaux sont aussi rapides que les vector. Mais dans certains cas, vector est plus rapide.

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    Bonjour,
    Citation Envoyé par r0d Voir le message
    De façon générale, les tableaux sont aussi rapides que les vector. Mais dans certains cas, vector est plus rapide.
    Euh... Quoi ???

    vector représente un tableau, en interne il s'agit d'un tableau tout ce qu'il y a de plus classique, maquillé pour contenir des fonctions et le modifier.
    les seules actions "lentes" de vector sont l'ajout d'élément, quand une réallocation est nécessaire.
    Dans tous les cas, vector ne sera pas plus rapide qu'un C-Array, puisqu'il ajoute une indirection. Mais on peut compter sur l'inline etc afin d'optimiser tout ça et que ça passe (complètement) inaperçu.

    Le mieux étant de réserver la taille suffisante, pour qu'aucune réallocation ne soit faite avec les ajouts à venir, avec vector::reserve

    Ce que je ne comprend pas, étant donné que je l'initialise avec la variable "slice" qui n'a rien à voir avec "max".
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int limite = ceil(sqrt(max));
    if(max > 10000)
    slice = 10000;
    else
    slice = limite;
    slice dépend de max

    Le pourquoi du crash me dépasse par contre, que dit le debuger ?
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    r0d
    r0d est déconnecté
    Membre expérimenté

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2004
    Messages
    4 294
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2004
    Messages : 4 294
    Billets dans le blog
    2
    Par défaut
    Il me semble que la move semantic, déjà utilisée dans certaines implémentations de std::vector, permet de gagner du temps dans certains cas.

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2005
    Messages
    69
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2005
    Messages : 69
    Par défaut
    Merci pour vos réponses.

    J'ai déjà essayé de faire un simple vector<int> segment(slice), sans mettre de valeur d'initialisation, ça foire toujours.

    Je compile sous MinGW, la dernière version en date.

    Je précise, après avoir posté hier j'ai essayé de faire comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
     
    std::vector<int> segment(slice,1);
     
    for(int y = limite; y <= max;y+=slice)
    {
        if(y + slice + limite > max)
        {
            segment.resize(slice - limite);
        }
     
     
        for(int z = 0; z <= (int)segment.size(); z++)
        {
            if(z % 2 == 0)
            segment[z] = 0;
            else
            {
                segment[z] = z + y;
            }
        }
     
        for(int g = 3; g <= limite; g+=2)
        {
            if(tableau[g] == 0x1)
            {
                for(int h = 1;h <= (int)segment.size();h++)
                {
     
                if(segment[h] != 0)
                {
                    if(segment[h] % g == 0)
                    segment[h] = 0;
                }
     
     
                }
            }
        }
        for(int r = 1; r <= (int)segment.size();r++)
        {
            if(segment[r] != 0)
            {
                compteur2++;
     
            }
        }
     
    }
    J'ai donc fais un resize dans le cas où y + slice dépasserait la valeur de max. Maintenant le code marche, sauf quand max = 200.000 ou 1.000.000. Ce qui est relativement étrange

    (EN ce qui concerne la relation entre max et slice, comme tu remarques, slice est toujours égal à 10.000 dans chacun de mes test, vu que max est toujours supérieur à 10.000).

    Le debugger indique :

    "Program received signal SIGTRAP, Trace/breakpoint trap.
    In ntdll!TpWaitForAlpcCompletion () (C:\Windows\system32\ntdll.dll)".

    Au fait, j'ai vu une source en C où le gars utilisait les fonctions malloc, memcpy, etc, pour allouer de façon dynamique la place nécessaire en mémoire. Est-ce plus rapide, ou simplement parcequ'il n'utilise pas le C++ ?

    EDIT : Bon pour 2.000.000 le programme plante aussi, mais pas pour 3 ou plus.

    EDIT 2 : Je remarque quelque chose, le programme plante, mais m'affiche le on nombre de premiers, ce qui veut dire qu'il plante après la boucle for principale, ce qui semble étrange.

    EDIT 3 : Encore plus étrange ! Le programme plante à 39204, 198917, 996005, 4972901. Il y a un facteur 5 (à peu près, de 4.99 à 5.07) entre chacun de ces nombres. Théorie du complot ?

  6. #6
    Membre éclairé
    Homme Profil pro
    Étudiant
    Inscrit en
    Avril 2011
    Messages
    274
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Avril 2011
    Messages : 274
    Par défaut
    Parfois le comportement d'un programme peut sembler étrange lorsqu'on corrompt la mémoire

    Tu essaies en effet de modifier l'accès à un emplacement non permis lorsque tu déclares :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    for(int z = 0; z < slice; z++)
        {
            [...]
           segment[z] = 0;
        }
    Essaie plutôt ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    for(int y = limite; y <= max;y+=slice)
    {
        for(int z = 0; z < slice; z++)
        {
            if(z % 2 == 0)
            segment[z] = 0;
            else
            {
                if(z+y < max)
                segment[z] = z + y;
                else
                segment[z] = 0;
            }
        }
     
        for(int g = 3; g <= limite; g+=2)
        {
            if(tableau[g] == 0x1)
            {
                for(int h = 1;h < slice;h++)
                {
     
                if(segment[h] != 0)
                {
                    if(segment[h] % g == 0)
                    segment[h] = 0;
                }
     
     
                }
            }
        }
        for(int r = 0; r < slice;r++)
        {
            if(segment[r] != 0)
            {
                compteur2++;
     
            }
        }
     
    }
    C'est à dire avec des inférieurs stricts dans les for. Tu peux également mettre des unsigned int à la place des int et faire de nombreuses petites optimisations mais je pense que tu t'en doute

    PS :
    Au fait, j'ai vu une source en C où le gars utilisait les fonctions malloc, memcpy, etc, pour allouer de façon dynamique la place nécessaire en mémoire. Est-ce plus rapide, ou simplement parce qu'il n'utilise pas le C++ ?
    C'est pour le C n'utilise jamais ça en c++ ^^ même si c'est possible ce n'est vraiment pas recommandé

Discussions similaires

  1. [Turbo Pascal] Crible d'Eratosthène (Nombres premiers)
    Par Conreik dans le forum Turbo Pascal
    Réponses: 8
    Dernier message: 24/01/2014, 12h35
  2. Problème avec le Crible d'Eratosthène. :s
    Par Crunsky dans le forum Langage
    Réponses: 4
    Dernier message: 04/01/2008, 13h47
  3. [VB6] [Interface] Horloge 7 segments
    Par selenay dans le forum VB 6 et antérieur
    Réponses: 11
    Dernier message: 07/10/2002, 16h15
  4. [TASM] Déclarer le segment de pile
    Par cipher dans le forum x86 16-bits
    Réponses: 2
    Dernier message: 01/10/2002, 03h58
  5. angle entre 2 segments
    Par tane dans le forum Mathématiques
    Réponses: 4
    Dernier message: 25/09/2002, 16h47

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo