Вы находитесь на странице: 1из 0

Centre Informatique pour les Lettres

et les Sciences Humaines


Apprendre C++ avec Qt : Annexe 2
Utilisation de nombres pseudo-alatoires

Il arrive assez frquemment que l'on souhaite utiliser des nombres "alatoires", tirs dans un
intervalle donn. La librairie standard propose la fonction r and( ) , qui renvoie un nombre
entier compris dans l'intervalle [ 0, RAND_MAX] . L'utilisation de cette fonction implique de
prendre en charge plusieurs dtails qui permettent de l'adapter aux besoins rencontrs.

Pour utiliser dans vos propres projets les fonctions dcr i t es dans ce document , il vous
suffit d'en copier le corps dans une fonction que vous aurez pralablement cre (il peut s'agir
soit d'une fonction globale, soit d'une fonction membre d'une classe, selon vos besoins). Les
oprations copier/coller tant trs mal prises en charge par Adobe Acrobat Reader, le code de
ces fonctions est galement disponible sous la forme d'un fichier texte.
1 - Amorage du gnrateur
Si l'on ne souhaite pas obtenir la mme squence de nombres chaque excution du
programme, il faut "amorcer" le gnrateur de nombres pseudo-alatoires. Dans la librairie
standard, c'est la fonction sr and( ) qui est charge de cet amorage. La fonction sr and( ) n'est
pas plus capable de gnrer un nombre authentiquement alatoire que ne l'est r and( ) : pour
que l'amorage effectu ne soit pas toujours le mme (et donc ne conduise pas la mme
squence de nombres pseudo-alatoires chaque excution), il convient de transmettre
sr and( ) un paramtre dont nous ayons bon espoir qu'il sera diffrent lors de chaque excution
du programme. La solution traditionnellement adopte est d'utiliser la fonction t i me( ) , qui
renvoie le nombre de secondes sparant le 1er janvier 1970, 0 heures, du moment de l'appel de
la fonction
1
.

sr and( t i me( NULL) ) ; / / amor age de r and( ) l ' ai de de l ' heur e cour ant e

Les fonctions r and( ) et sr and( ) sont dclares dans le fichier stdlib.h, qui contient
galement la dfinition de la constante RAND_MAX. La fonction t i me( ) est, pour sa part,
dclare dans le fichier time.h. Selon le compilateur utilis et le type de projet en cours, il
peut tre ncessaire de faire figurer explicitement les directives #i ncl ude appropries au
dbut des fichiers dans lesquels ces fonctions et/ou cette constante sont utilises.

L'amorage du gnrateur de nombres pseudo-alatoires ne doit tre effectu qu'une seule fois
au cours de l'excution du programme, faute de quoi le caractre "alatoire" des nombres
renvoys par r and( ) risque de disparatre.
2 - Tirage d'une srie de valeurs
Une fois le gnrateur amorc, on peut utiliser la fonction r and( ) pour obtenir un nombre Si
l'on dispose d'une fonction af f i che( ) capable d'afficher l'cran des valeurs entires,
l'excution du fragment de code suivant

/ / on suppose que sr and( ) a dj t appel e
i nt t i r age; 1
i nt n; 2
f or ( n=0 ; n < 50 ; n = n + 1) 3
{ 4
t i r age = r and( ) ; 5
af f i che( t i r age) ; 6
} 7

se traduira par l'apparition d'une srie du genre

1
Il ne s'agit donc pas simplement de l'heure, qui risque d'tre fcheusement constante si notre programme est lanc
automatiquement tous les jours la mme heure...
Document du 21/12/04 - Retrouvez la version la plus rcente sur http://www.up.univ-mrs.fr/wcpp
C++ - Annexe 2 Nombres pseudo-alatoires 2/3

16682 795 29983 21753 15209 16146 29791 9228 13562 13890 6752 27027 12034
5265 5507 17471 4098 7880 28280 21710 1357 24124 5460 26321 6336 12207 17635
5811 20141 14705 12351 6391 24600 3274 11937 1729 25894 30365 22904 21400 978
17221 20664 20586 30434 31171 6517 24528 281 21019
3 - Contrle de la plage de valeurs admissibles
La fonction r and( ) n'ayant aucun argument, il n'est pas possible de contrler directement
l'intervalle des valeurs possibles pour un tirage.

i nt unI nt = r and( ) ; / / unI nt est dans l ' i nt er val l e [ 0, RAND_MAX]

Dans la plupart des cas, un traitement s'impose donc, pour ramener la valeur renvoye par
r and( ) dans l'intervalle qui nous intresse
2
. La fonction suivante est capable de tirer un
nombre compris entre des bornes qui lui sont communiques par passage de paramtres :

i nt unI nt Ent r e( i nt a, i nt b) 1
{ 2
i nt mi ni mum= a; 3
i nt i nt er val l e = b - a; 4
i f ( a > b) 5
{ 6
mi ni mum= b; 7
i nt er val l e = a - b; 8
} 9
r et ur n mi ni mum+ ( r and( ) %i nt er val l e) ; 10
} 11

Remarquez que, si r and( ) renvoie parfois RAND_MAX, la fonction unI nt Ent r e( ) ne renvoie
JAMAIS une valeur gale au paramtre max, ce qui signifie que, lorsque mi n vaut 0,
unI nt Ent r e( ) a exactement max valeurs diffrentes possibles.

Le fragment de code suivant est exemple d'utilisation de la fonction unI nt Ent r e( ) . Il simule
30 lancs successifs d'un d 6 faces, dont les rsultats sont stocks dans une QVal ueLi st :

/ / on suppose que sr and( ) a dj t appel e
QVal ueLi st <i nt > l esVal eur s; 1
whi l e ( l esVal eur s. count ( ) < 30) 2
l esVal eur s. append( unI nt Ent r e( 1, 7) ) ; 3

L'excution de cette squence placera dans la liste une srie du genre :

2 1 3 4 4 6 4 4 6 6 3 4 2 2 4 5 1 3 3 4 2 2 5 1 6 1 4 1 6 6
4 - Tirage sans remise
La fonction r and( ) n'est capable d'effectuer que des tirages indpendants les uns des autres.
En d'autres termes, r and( ) fonctionne comme un d qui aurait RAND_MAX+1 faces : lors d'un
lanc, la valeur obtenue lors du lanc prcdent autant de chances d'apparatre que
n'importe quelle autre valeur.

Cette situation est trs diffrente de celle rencontre, par exemple, lorsqu'on distribue des
cartes : la probabilit qu'un joueur reoive une carte identique une carte dj attribue un
autre joueur est alors nulle. Lorsqu'un programme exige un tirage de ce type (ce qu'on appelle
un tirage "sans remise"), il est ncessaire d'en assurer explicitement la gestion.

La fonction suivante stocke dans une QVal ueLi st des valeurs diffrentes les unes des autres,
tires dans un intervalle dont les bornes lui sont (tout comme la QVal ueLi st et le nombre de
valeur tirer) communiques par passage de paramtres :


2
Oubliez tout de suite, si vous l'avez eu, l'ide de changer la dfinition de la constante RAND_MAX. Cette constante, tout
comme I NT_MAX ou CLOCKS_PER_SEC, n'est l que pour vous permettre d'crire du code indpendant des
caractristiques du compilateur, et en aucun cas pour vous permettre de connatre ou de modifier les valeurs en
questions.
J-L Pris - 21/12/04
C++ - Annexe 2 Nombres pseudo-alatoires 3/3
bool t i r eSansRemi se( QVal ueLi st <i nt > &l i st e, unsi gned i nt nbVal , i nt a, i nt b) 1
{ 2
l i st e. cl ear ( ) ; 3
i nt mi n = a; 4
i nt max = b; 5
i f ( mi n > max) 6
{ 7
mi n = b; 8
max = a; 9
} 10
i f ( nbVal > max - mi n) / / mi ssi on i mpossi bl e ! 11
r et ur n f al se; 12
/ / f abr i cat i on d' une ur ne cont enant l es val eur s de mi n max, dans l ' or dr e cr oi ssant
i nt i ; 13
QMap <i nt , i nt > ur ne; 14
f or ( i = mi n ; i < max; ++i ) 15
ur ne[ i - mi n] = i ; 16
/ / t i r age sans r emi se
i nt l i mi t eTi r age = ur ne. count ( ) ; 17
f or ( i =0 ; i < nbVal ; ++i ) 18
{ 19
i nt posi t i onTi r ee = unI nt Ent r e( 0, l i mi t eTi r age) ; 20
l i st e. append( ur ne[ posi t i onTi r ee] ) ; 21
ur ne[ posi t i onTi r ee] = ur ne[ - - l i mi t eTi r age] ; 22
} 23
r et ur n t r ue; / / si gnal e que t out s' est bi en pass 24
} 25

Cette fonction s'assure qu'une valeur donne ne figurera pas deux fois dans la liste en
simulant la prsence d'une urne, dans laquelle les valeurs utilises seraient tires : chaque
fois qu'une valeur est place dans la liste, elle est galement rendue indisponible en la
remplaant dans l'urne par celle dont la position va tre rendue inaccessible lors du tirage
suivant.

La fonction t i r eSansRemi se( ) peut tre utilise pour obtenir un nombre quelconque de
valeurs, toutes diffrentes, tires d'un intervalle quelconque ( condition, bien entendu, que cet
intervalle comporte au moins autant de valeurs qu'il en est demand).

Dans l'exemple suivant, la liste est garnie avec dix valeurs tires dans l'intervalle [0, 32[, ce qui
pourrait s'apparenter tirer 10 cartes dans un jeu de 32 :

/ / on suppose que sr and( ) a dj t appel e
QVal ueLi st <i nt > l esVal eur s; 1
t i r eSansRemi se( l esVal eur s, 10, 0, 32) ; 2

L'excution de cette squence placera dans la liste une srie du genre :

22 3 21 19 10 17 20 13 6 28

Remarquez que, si le nombre de valeurs demandes est gal la taille de l'intervalle de tirage,
appeler la fonction t i r eSansRemi se( ) revient mlanger les valeurs plutt qu' en choisir
certaines :

QVal ueLi st <i nt > val eur sDansLeDesor dr e;
t i r eSansRemi se( val eur sDansLeDesor dr e, 32, 0, 32) ;

produira une srie du type

23 24 17 30 8 26 1 20 4 29 10 31 28 6 0 9 2 5 7 27 21 25 22 19 13 18 11 15
16 3 14 12

J-L Pris - 21/12/04

Вам также может понравиться