tirage aléatoire sans remise

tirage aléatoire sans remise - C - Programmation

Marsh Posté le 16-12-2004 à 15:47:03    

Bonjour, j'aimerais tirer au hasard 6 valeurs sur un ensemble de 12 valeurs. Je fais entrer les 12 valeurs manuellement mais mon programme bug. Quand je l'execute y'a genre une violation d'adresse ou un truc du genre. (Pour le fopen c'est juste que quand ca marchera j'utiliserais un fichier pour enregistrer les résultats)

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. int main ()
  6. {
  7. FILE *fichier;
  8. float ligne [12];
  9. int i,t,k;
  10. int j[6];
  11. int test=0;
  12. float somme=0;
  13. srand(time(NULL)); //initialisation de la fonction rand
  14. fichier=fopen("essai2.txt","w" );
  15. /*entree des 12 valeurs*/
  16. for(i=0;i<12;i++)
  17. {
  18.     printf("valeur%d:",i);
  19.       scanf("%f", &ligne[i]);
  20.       fprintf(fichier,"valeur%d: %.4f\n",i,ligne[i]);
  21.       getchar();
  22.    }
  23. /*tirage aléatoire*/
  24. for(t=0;t<6;t++)
  25.  {
  26.        while(test==0)
  27.           {
  28.             j[t]=rand()%12;
  29.             test=1;
  30.             if (t>0)
  31.              {
  32.              for(k=0;k<t;k++)
  33.               {
  34.                  printf("k:%d\t",k);
  35.                    printf("t:%d\t",t);
  36.                  if (j[t]==j[k])
  37.                     {
  38.                        j[t]=rand()%12;
  39.                          test=0;
  40.                       }
  41.                   }
  42.                }
  43.           }
  44.  }
  45.       for(t=0;t<6;t++)
  46.       {
  47.        printf("%d\n",j[t]);
  48.        printf("%.4f\n",ligne[j[t]]);//cette ligne est surlignée quand le programme bloque
  49.        //somme= somme + ligne[j[t]];
  50.        //printf("%f\n",somme);
  51.       }
  52.       somme= somme/6;
  53.       printf("%.4f\n",somme);
  54. fclose (fichier);
  55. getchar();
  56. return 0;
  57.    }


 
 

Reply

Marsh Posté le 16-12-2004 à 15:47:03   

Reply

Marsh Posté le 16-12-2004 à 16:05:01    

J'ai même pas envie de dérouler ton algo. Pourquoi tu ne le fais pas de façon plus claire et plus rapide en:

Pour i=1 à 6
    t[i]=valeur utilisateur.
 
Pour i=1 à 12 // ou bien 6 pour être feignasse
    int newPos = rand()%12;
    int temp = t[i]
    t[i]=t[newPos]
    t[newPos]=temp


Message édité par Lam's le 16-12-2004 à 16:05:45
Reply

Marsh Posté le 16-12-2004 à 16:07:31    

Lam's a écrit :

J'ai même pas envie de dérouler ton algo. Pourquoi tu ne le fais pas de façon plus claire et plus rapide en:

Pour i=1 à 6
    t[i]=valeur utilisateur.
 
Pour i=1 à 12 // ou bien 6 pour être feignasse
    int newPos = rand()%12;
    int temp = t[i]
    t[i]=t[newPos]
    t[newPos]=temp




Peut-être parce-que ça fait pas la même chose? [:urd]


---------------
Can't buy what I want because it's free -
Reply

Marsh Posté le 16-12-2004 à 16:10:55    

skeye a écrit :

Peut-être parce-que ça fait pas la même chose? [:urd]


J'ai pas l'impression que son code assure la non-remise, vu qu'il n'inverse pas les valeurs (à part la boucle k bidule, que j'ai la flemme de comprendre).

Reply

Marsh Posté le 16-12-2004 à 16:18:29    

c le but de la boucle K bidule. Sinon c'est bien plus simple effectivement  :p

Reply

Marsh Posté le 18-12-2004 à 08:45:30    

J'ai matté ton algo et j'ai pas vraiment trouvé d'erreur.
T'as pas de debuggeur pour voir exactement les valeurs que prennent les variables ?
 
Tu peux faire la meme chose avec 3-4 lignes de moins mais si tu comprends mieux comme ca, tant mieux : chacun ses méthodes  ;)  

Reply

Marsh Posté le 18-12-2004 à 11:01:52    

CCIman a écrit :


Code :
  1. <snip>



Voilà un cas assez typique de code difficile à lire parce qu'il ne respecte pas un principe de codage simple qui veut que la portée d'un objet doit être limitée au strict nécessaire.
 
Je propose de réécrire ce code (la sémantique est inchangée) selon ce principe, ce qui AMA le rend immédiatement plus clair. (J'ai ajouté mes habituels manies : commentaires C90, suppression des accents et réindentation) :

Code :
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <time.h>
  5. int main (void)
  6. {
  7.    float ligne[12];
  8.    srand ((int) time (NULL));   /* initialisation de la fonction rand */
  9. /* entree des 12 valeurs */
  10.    {
  11.       FILE *fichier = fopen ("essai2.txt", "w" );
  12.       if (fichier != NULL)
  13.       {
  14.          int i;
  15.          for (i = 0; i < 12; i++)
  16.          {
  17.             printf ("valeur%d:", i);
  18.             scanf ("%f", ligne + i);
  19.             (void) getchar ();
  20.             fprintf (fichier, "valeur%d: %.4f\n", i, ligne);
  21.          }
  22.          fclose (fichier);
  23.       }
  24.    }
  25. /* tirage aleatoire */
  26.    {
  27.       int j[6];
  28.       {
  29.          int test = 0;
  30.          int t;
  31.          for (t = 0; t < 6; t++)
  32.          {
  33.             while (test == 0)
  34.             {
  35.                j[t] = rand () % 12;
  36.                test = 1;
  37.                if (t > 0)
  38.                {
  39.                   int k;
  40.                   for (k = 0; k < t; k++)
  41.                   {
  42.                      printf ("k:%d\t", k);
  43.                      printf ("t:%d\t", t);
  44.                      if (j[t] == j[k])
  45.                      {
  46.                         j[t] = rand () % 12;
  47.                         test = 0;
  48.                      }
  49.                   }
  50.                }
  51.             }
  52.          }
  53.       }
  54.       {
  55.          float somme = 0;
  56.          int t;
  57.          for (t = 0; t < 6; t++)
  58.          {
  59.             printf ("%d\n", j[t]);
  60.             printf ("%.4f\n", ligne[j[t]]);  /* cette ligne est surlignee quand le programme bloque */
  61.             /* somme= somme + ligne[j[t]]; */
  62.             /* printf("%f\n",somme); */
  63.          }
  64.          somme = somme / 6;
  65.          printf ("%.4f\n", somme);
  66.       }
  67.    }
  68.    (void) getchar ();
  69.    return 0;
  70. }


Autre avantage de cet écriture, la préparation du code à un découpage en fonction...
 
J'ai placé un point d'arrêt en ligne 67 pour visualiser le contenu de j:


+-[_]----- Inspecting j ---4-[]-+
¦8FD6:0FC0                       
¦[0]                 11 (0x000B) _
¦[1]               9455 (0x24EF) _
¦[2]             -30009 (0x8AC7) _
¦[3]             -30025 (0x8AB7) _
¦[4]               1664 (0x0680) _
¦[5]                512 (0x0200) 
Ã-____________________________-Â
¦int [6]                         ¦
+--------------------------------+


Y'a un problème! (la valeur devrait être comprise entre 0 et 11)
Comme le contenu de 'j' sert d'index au tableau ligne, je comprend que ça casse! Il y a un bug dans l'algo de tirage. Pourquoi n'a-t-il pas été  validé individuellement ?
 
En fait, c'est simple. Au premier tour, 'test' est forcé à 1 (ligne 44). Ensuite, while (test == 0) est toujours faux, et on n'écrit jamais dans j[1]-j[5], ce qui explique la trace ci-dessus...
 
Voici un exemple de validation (au moins visuelle) de l'algorithme:
 
L'interface:

Code :
  1. #ifndef H_TIRAGE
  2. #define H_TIRAGE
  3. /* tirage.h */
  4. #include <stddef.h>
  5. void tirage (int *a, size_t n, int max);
  6. #endif /* guard */


L'implementation:

Code :
  1. /* tirage.c */
  2. #include "tirage.h"
  3. #include <stdlib.h>
  4. #ifdef TEST
  5. #include <stdio.h>
  6. static void print (int const *a, size_t n)
  7. {
  8.    size_t i;
  9.    for (i = 0; i < n; i++)
  10.    {
  11.       printf ("a[%u]=%d\n", (unsigned) i, a[i]);
  12.    }
  13. }
  14. #endif
  15. static doublon(int *a, size_t n, int x)
  16. {
  17.    int found = 0;
  18.    size_t i;
  19.    for (i = 0; !found && i < n; i++)
  20.    {
  21.       found = a[i] == x;
  22.    }
  23.    return found;
  24. }
  25. void tirage (int *a, size_t n, int max)
  26. {
  27.    size_t i;
  28.    for (i = 0; i < n; i++)
  29.    {
  30.       if (i == 0)
  31.       {
  32.          a[i] = rand () % max;
  33.       }
  34.       else
  35.       {
  36.          int x;
  37.          do
  38.          {
  39.             x = rand () % max;
  40.          }
  41.          while (doublon(a, i, x));
  42.          a[i] = x;
  43.       }
  44.    }
  45. }
  46. #ifdef TEST
  47. int main (void)
  48. {
  49.    int j[6];
  50.    tirage (j, sizeof j / sizeof *j, 12);
  51.    print (j, sizeof j / sizeof *j);
  52.    return 0;
  53. }
  54. #endif


Pour faire le test, compiler tirage.c avec -DTEST


D:\DEV-CPP\ED\001>bc tirage.prj
a[0]=10
a[1]=2
a[2]=4
a[3]=1
a[4]=3
a[5]=7


Evidemment, on obtient toujours le même résultat poutr implémentation donnée (ici Borland C 3.1) On peut améliorer avec srand()...
 
Ensuite, dans l'applicaion, on inclus "tirage.h", et on ajoute tirage.c dans le projet. On appelle la fonction tirage avec le parametres qui vont bien.
 
Le travail en module indépendants et testables et indispensable si on veut écrire du code sérieusement. De plus, la modularité permet souvent la réutilisation d'objet validés, ce qui est un avantage certain que ce soit pour le développeur, son employeur ou le client final :  

  • développement plus rapide.
  • augmentation de la fiabilité.
  • amortissement des coûts de développement.


[i]Nota : le micro test que j'ai indiqué n'est qu'un embryon d'ébauche de début de test de validation unitaire... Dans la réalité, c'est beaucoup plus 'velu!'


Message édité par Emmanuel Delahaye le 18-12-2004 à 11:55:42

---------------
Des infos sur la programmation et le langage C: http://www.bien-programmer.fr Pas de Wi-Fi à la maison : http://www.cpl-france.org/
Reply

Marsh Posté le 31-12-2004 à 00:33:22    

merci beaucoup pour ce mini cours  :jap:

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed