Fonction c
Résolu ahmoude Messages postés 3 Date d'inscription Statut Membre Dernière intervention -
mype Messages postés 2435 Date d'inscription Statut Membre Dernière intervention - 15 déc. 2007 à 00:03
mype Messages postés 2435 Date d'inscription Statut Membre Dernière intervention - 15 déc. 2007 à 00:03
A voir également:
- Fonction c
- Fonction si et - Guide
- Fonction miroir - Guide
- Fonction moyenne excel - Guide
- Fonction somme excel - Guide
- Fonction remplacer sur word - Guide
9 réponses
Salut,
la technique de Mype n'est pas la meilleure car tu n'obtiendras pas des nombres pseudo-aleatoires satisfaisants... d'ailleurs les nombres aleatoires des bibliotheques C/C++ sont pas top en général... En plus il faut initialiser le generateur EN DEHORS de l'appel de la fontion sinon tu obtiendras toujours le meme nombre... :/
Je conseille plutot ceci :
#include <stdlib.h> // <--- contient les fonctions srand() et rand()
#include <time.h> // <--- contient la fonction time()
#include <stdio.h> // <--- pour utiliser printf() :-D
int initaleat() {
srand( time(NULL) ); // Ceci initialise le générateur de nbres pseudo-aléatoires
}
int aleat() {
int nb;
nb = ( (rand() * 18 ) / RAND_MAX ) + 3 ;
return nb ;
}
int main() {
initaleat();
// Ici tes appels a la fonction aleat, genre :
printf("%d",aleat());
}
a+
-Qwerti.
la technique de Mype n'est pas la meilleure car tu n'obtiendras pas des nombres pseudo-aleatoires satisfaisants... d'ailleurs les nombres aleatoires des bibliotheques C/C++ sont pas top en général... En plus il faut initialiser le generateur EN DEHORS de l'appel de la fontion sinon tu obtiendras toujours le meme nombre... :/
Je conseille plutot ceci :
#include <stdlib.h> // <--- contient les fonctions srand() et rand()
#include <time.h> // <--- contient la fonction time()
#include <stdio.h> // <--- pour utiliser printf() :-D
int initaleat() {
srand( time(NULL) ); // Ceci initialise le générateur de nbres pseudo-aléatoires
}
int aleat() {
int nb;
nb = ( (rand() * 18 ) / RAND_MAX ) + 3 ;
return nb ;
}
int main() {
initaleat();
// Ici tes appels a la fonction aleat, genre :
printf("%d",aleat());
}
a+
-Qwerti.
Salut Mype,
Désolé si j'ai eu l'air de déprecier ce que tu as écrit, ce n'était pas du tout mon but !
Cependant :
Pour l'initialisation j'aime mieux qu'elle soit ailleurs que dans la fonction aleat() elle-meme, juste au cas ou l'on décide au dernier moment de tirer 2 nombres aléatoires au lieu d'un... ca peut arriver :-D
Il y a une différence avec ce que tu as fait : je n'ai pas utilisé l'operateur modulo ( % ). Il se trouve qu'on obtient une distribution désastreuse si l'on s'en sert...
a+
-Qwerti.
Désolé si j'ai eu l'air de déprecier ce que tu as écrit, ce n'était pas du tout mon but !
Cependant :
Pour l'initialisation j'aime mieux qu'elle soit ailleurs que dans la fonction aleat() elle-meme, juste au cas ou l'on décide au dernier moment de tirer 2 nombres aléatoires au lieu d'un... ca peut arriver :-D
Il y a une différence avec ce que tu as fait : je n'ai pas utilisé l'operateur modulo ( % ). Il se trouve qu'on obtient une distribution désastreuse si l'on s'en sert...
a+
-Qwerti.
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question Mype,
Un exemple simple (pas tres realiste mais bon...)
Imagine tu as un generateur de nombres pseudo-aleatoires rand() qui donne des nombres entre 0 et 18.
Si tu fais
nb = ( rand() % 18 + 3 );
il est clair que 3 va arriver avec la probabilité 2/19 et les autres nombres entre 4 et 20 avec la probabilité 1/19, ce qui n'est pas top d'un point de vue equidistribution.
Autre chose que D. Knuth souleve dans son bouquin "The Art Of Computer Programmming vol. 2" (excellent chapitre sur les nombres aleatoires !!! un must !) : les LSB ne sont pas bien distribués...
Pour une "bonne" distribution, le mieux est de "normaliser" les nombres entre 0 et 1 comme ca :
rand() / RAND_MAX ;
( RAND_MAX est la valeur max prise par la fonction rand() )
puis de multiplier par l'amplitude souhaitée (ici 18) puis faire le décalage (3 dans notre exemple).
J'espere que je suis pas trop confus dans mes explications.
a+
-Qwerti.
Un exemple simple (pas tres realiste mais bon...)
Imagine tu as un generateur de nombres pseudo-aleatoires rand() qui donne des nombres entre 0 et 18.
Si tu fais
nb = ( rand() % 18 + 3 );
il est clair que 3 va arriver avec la probabilité 2/19 et les autres nombres entre 4 et 20 avec la probabilité 1/19, ce qui n'est pas top d'un point de vue equidistribution.
Autre chose que D. Knuth souleve dans son bouquin "The Art Of Computer Programmming vol. 2" (excellent chapitre sur les nombres aleatoires !!! un must !) : les LSB ne sont pas bien distribués...
Pour une "bonne" distribution, le mieux est de "normaliser" les nombres entre 0 et 1 comme ca :
rand() / RAND_MAX ;
( RAND_MAX est la valeur max prise par la fonction rand() )
puis de multiplier par l'amplitude souhaitée (ici 18) puis faire le décalage (3 dans notre exemple).
J'espere que je suis pas trop confus dans mes explications.
a+
-Qwerti.
il est clair que 3 va arriver avec la probabilité 2/19 et les autres nombres entre 4 et 20 avec la probabilité 1/19, ce qui n'est pas top d'un point de vue equidistribution.
pas du tout les nombres ont la meme probabilite dans ce cas
car (rand() % 18) tire un nombre entre 0 et 18 et ensuite on ajoute 3
ce qui fait si le nombre tiré est 0 on a 3
si le nombre tiré est 3 on a 6
donc tous les nombre entre 3 et 20 ont la meme probabilité d'etre (1/19) ( c'est tjr ce qu'on m'a appris...)
mais peu etre que tu as raison... ;)
mais bon je critique pas ta solution non plus elle est juste c'est juste que je la trouve un peu trop longue surtout pr un debutant et le principale peu importe la metjode c'est qu'il a resolu son probleme ;)
pas du tout les nombres ont la meme probabilite dans ce cas
car (rand() % 18) tire un nombre entre 0 et 18 et ensuite on ajoute 3
ce qui fait si le nombre tiré est 0 on a 3
si le nombre tiré est 3 on a 6
donc tous les nombre entre 3 et 20 ont la meme probabilité d'etre (1/19) ( c'est tjr ce qu'on m'a appris...)
mais peu etre que tu as raison... ;)
mais bon je critique pas ta solution non plus elle est juste c'est juste que je la trouve un peu trop longue surtout pr un debutant et le principale peu importe la metjode c'est qu'il a resolu son probleme ;)
Attention je pense qu'il y a un bug dans ton raisonnement Mype !
Reprend mon exemple :
Imagine rand() ne tire que des nombres (entiers) entre 0 et 18 (inclus).
Ainsi, chaque entiers entre 0 et 18 a un probabilité de 1/19 (il y 19 nombres, qu'on suppose equidistribués).
Maintenant,
nb = rand() % 18 ;
est un nombre entre 0 et 17 (inclus) et ca marche comme ca :
Si rand() == 0, alors nb = 0 ;
Si rand() == 1, alors nb = 1 ;
Si rand() == 2, alors nb = 2 ;
etc...
Si rand() == 17, alors nb = 17;
Enfin, si rand() == 18, alors nb = 0 ; // (car 18 % 18 = 0).
J'espere que la c'est clair que nb == 0 sort avec la probabilité 2/19 (car on obtient 0 de 2 manieres differentes : lorsque rand() == 0 et lorsque rand() == 18, chacun ont la proba 1/19 donc la proba de nb == 0 est 1/19+1/19 = 2/19). Par contre, tous les autres entiers sortent avec la proba 1/19.
Est-ce clair ? :/
a+
-Qwerti.
Reprend mon exemple :
Imagine rand() ne tire que des nombres (entiers) entre 0 et 18 (inclus).
Ainsi, chaque entiers entre 0 et 18 a un probabilité de 1/19 (il y 19 nombres, qu'on suppose equidistribués).
Maintenant,
nb = rand() % 18 ;
est un nombre entre 0 et 17 (inclus) et ca marche comme ca :
Si rand() == 0, alors nb = 0 ;
Si rand() == 1, alors nb = 1 ;
Si rand() == 2, alors nb = 2 ;
etc...
Si rand() == 17, alors nb = 17;
Enfin, si rand() == 18, alors nb = 0 ; // (car 18 % 18 = 0).
J'espere que la c'est clair que nb == 0 sort avec la probabilité 2/19 (car on obtient 0 de 2 manieres differentes : lorsque rand() == 0 et lorsque rand() == 18, chacun ont la proba 1/19 donc la proba de nb == 0 est 1/19+1/19 = 2/19). Par contre, tous les autres entiers sortent avec la proba 1/19.
Est-ce clair ? :/
a+
-Qwerti.
mais rand() ne s'arrete pas a 18 il vas jusqu'a RANDMAX
ce qui fait qu'il n'y pas que 0 qui se repete mais tous les nombres jusqu'a 17 se repete plusieurs fois
donc tu a toute une liste de nombres comme ça
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2...17 0 1 2... 17
et ensuite un nb est tiré au hasard parmis cette liste et ds cette liste 0 se repete autant de fois que 4 ou 17 ou n'importe qu'elle nombre
il y a donc bien une equiprobabilité
ce qui fait qu'il n'y pas que 0 qui se repete mais tous les nombres jusqu'a 17 se repete plusieurs fois
donc tu a toute une liste de nombres comme ça
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 0 1 2...17 0 1 2... 17
et ensuite un nb est tiré au hasard parmis cette liste et ds cette liste 0 se repete autant de fois que 4 ou 17 ou n'importe qu'elle nombre
il y a donc bien une equiprobabilité
Oui oui oui mype, je sais bien que rand() ne s'arrete pas a 18, mais dans mon exemple j'ai justement supposé que RAND_MAX = 18 :-)
Mais le coup du "modulo" ( % ) c'est pas top aussi a cause du fait que les chiffres les moins significatifs ne sont pas bien distribués (et tu utilises justement les chiffres les moins significatifs en utilisant l'operateur "modulo" ( % ) ). Par contre, faire :
int nb = rand() / RAND_MAX * 18 ;
ca utilise les chiffres les plus significatifs qui sont mieux distribues.
Je te conseille tres vivement la lecture de "The Art of Computer Programming vol. 2" de Donald KNUTH.
a+
-Qwerti.
PS. Quand tu dis que dans la liste 0 1 2 etc... 0 se repete autant de fois que les autres chiffres, ce n'est vrai que si (RAND_MAX+1) est divisible par 18. Sinon il y a un difference de 1/(RAND_MAX+1) entre certaines probabilites. Cest exactement ce que mon exemple illustre. Mais bon, je chipotte vraiment, car en general RAND_MAX est grand, et du coup 1/(RAND_MAX+1) est petit, et on peu vraiment le négliger. Lis le chapitre de KNUTH sur les nombres pseudo-aleatoires (un bouquin ionant !) et il explique pourquoi les LSB ne sont pas tres bien distribues et donc pourquoi ce n'est pas toujours bien d'utiliser %.
Mais le coup du "modulo" ( % ) c'est pas top aussi a cause du fait que les chiffres les moins significatifs ne sont pas bien distribués (et tu utilises justement les chiffres les moins significatifs en utilisant l'operateur "modulo" ( % ) ). Par contre, faire :
int nb = rand() / RAND_MAX * 18 ;
ca utilise les chiffres les plus significatifs qui sont mieux distribues.
Je te conseille tres vivement la lecture de "The Art of Computer Programming vol. 2" de Donald KNUTH.
a+
-Qwerti.
PS. Quand tu dis que dans la liste 0 1 2 etc... 0 se repete autant de fois que les autres chiffres, ce n'est vrai que si (RAND_MAX+1) est divisible par 18. Sinon il y a un difference de 1/(RAND_MAX+1) entre certaines probabilites. Cest exactement ce que mon exemple illustre. Mais bon, je chipotte vraiment, car en general RAND_MAX est grand, et du coup 1/(RAND_MAX+1) est petit, et on peu vraiment le négliger. Lis le chapitre de KNUTH sur les nombres pseudo-aleatoires (un bouquin ionant !) et il explique pourquoi les LSB ne sont pas tres bien distribues et donc pourquoi ce n'est pas toujours bien d'utiliser %.