"random" --- Generate pseudo-random numbers
*******************************************

**Code source :** Lib/random.py

======================================================================

Ce module implémente des générateurs de nombres pseudo-aléatoires pour
différentes distributions.

Pour les entiers, il existe une sélection uniforme à partir d'une
plage. Pour les séquences, il existe une sélection uniforme d'un
élément aléatoire, une fonction pour générer une permutation aléatoire
d'une liste sur place et une fonction pour un échantillonnage
aléatoire sans remplacement.

Pour l'ensemble des réels, il y a des fonctions pour calculer des
distributions uniformes, normales (gaussiennes), log-normales,
exponentielles négatives, gamma et bêta. Pour générer des
distributions d'angles, la distribution de *von Mises* est disponible.

Almost all module functions depend on the basic function "random()",
which generates a random float uniformly in the half-open range "0.0
<= X < 1.0". Python uses the Mersenne Twister as the core generator.
It produces 53-bit precision floats and has a period of 2**19937-1.
The underlying implementation in C is both fast and threadsafe.  The
Mersenne Twister is one of the most extensively tested random number
generators in existence.  However, being completely deterministic, it
is not suitable for all purposes, and is completely unsuitable for
cryptographic purposes.

Les fonctions fournies par ce module dépendent en réalité de méthodes
d’une instance cachée de la classe "random.Random". Vous pouvez créer
vos propres instances de "Random" pour obtenir des générateurs sans
états partagés.

Class "Random" can also be subclassed if you want to use a different
basic generator of your own devising: see the documentation on that
class for more details.

Le module "random" fournit également la classe "SystemRandom" qui
utilise la fonction système "os.urandom()" pour générer des nombres
aléatoires à partir de sources fournies par le système d'exploitation.

Avertissement:

  Les générateurs pseudo-aléatoires de ce module ne doivent pas être
  utilisés à des fins de sécurité.  Pour des utilisations de sécurité
  ou cryptographiques, voir le module "secrets".

Voir aussi:

  *M. Matsumoto and T. Nishimura, "Mersenne Twister: A
  623-dimensionally equidistributed uniform pseudorandom number
  generator", ACM Transactions on Modeling and Computer Simulation
  Vol. 8, No. 1,* Janvier pp.3--30 1998.

  Complementary-Multiply-with-Carry recipe for a compatible
  alternative random number generator with a long period and
  comparatively simple update operations.


Fonctions de gestion d'état
===========================

random.seed(a=None, version=2)

   Initialise le générateur de nombres aléatoires.

   Si *a* est omis ou "None", l'heure système actuelle est utilisée.
   Si des sources aléatoires sont fournies par le système
   d'exploitation, elles sont utilisées à la place de l'heure système
   (voir la fonction "os.urandom()" pour les détails sur la
   disponibilité).

   Si *a* est un entier, il est utilisé directement.

   Avec la version 2 (par défaut), un objet "str", "bytes" ou
   "bytearray" est converti en "int" et tous ses bits sont utilisés.

   Avec la version 1 (fournie pour reproduire des séquences aléatoires
   produites par d'anciennes versions de Python), l'algorithme pour
   "str" et "bytes" génère une gamme plus étroite de graines.

   Modifié dans la version 3.2: Passée à la version 2 du schéma qui
   utilise tous les bits d'une graine de chaîne de caractères.

   Modifié dans la version 3.11: The *seed* must be one of the
   following types: "None", "int", "float", "str", "bytes", or
   "bytearray".

random.getstate()

   Renvoie un objet capturant l'état interne actuel du générateur. Cet
   objet peut être passé à "setstate()" pour restaurer cet état.

random.setstate(state)

   Il convient que *state* ait été obtenu à partir d'un appel
   précédent à "getstate()", et "setstate()" restaure l'état interne
   du générateur à ce qu'il était au moment où "getstate()" a été
   appelé.


Fonctions pour les octets
=========================

random.randbytes(n)

   Génère *n* octets aléatoires.

   Cette méthode ne doit pas être utilisée pour générer des jetons de
   sécurité. Utiliser "secrets.token_bytes()" à la place.

   Ajouté dans la version 3.9.


Fonctions pour les entiers
==========================

random.randrange(stop)
random.randrange(start, stop[, step])

   Return a randomly selected element from "range(start, stop, step)".

   This is roughly equivalent to "choice(range(start, stop, step))"
   but supports arbitrarily large ranges and is optimized for common
   cases.

   The positional argument pattern matches the "range()" function.

   Keyword arguments should not be used because they can be
   interpreted in unexpected ways. For example "randrange(start=100)"
   is interpreted as "randrange(0, 100, 1)".

   Modifié dans la version 3.2: "randrange()" est plus sophistiquée
   dans la production de valeurs uniformément distribuées.
   Auparavant, elle utilisait un style comme "int(random()*n)" qui
   pouvait produire des distributions légèrement inégales.

   Modifié dans la version 3.12: Automatic conversion of non-integer
   types is no longer supported. Calls such as "randrange(10.0)" and
   "randrange(Fraction(10, 1))" now raise a "TypeError".

random.randint(a, b)

   Renvoie un entier aléatoire *N* tel que "a <= N <= b".  Alias pour
   "randrange(a, b+1)".

random.getrandbits(k)

   Returns a non-negative Python integer with *k* random bits. This
   method is supplied with the Mersenne Twister generator and some
   other generators may also provide it as an optional part of the
   API. When available, "getrandbits()" enables "randrange()" to
   handle arbitrarily large ranges.

   Modifié dans la version 3.9: Cette méthode accepte désormais zéro
   pour *k*.


Fonctions pour les séquences
============================

random.choice(seq)

   Renvoie un élément aléatoire de la séquence non vide *seq*. Si
   *seq* est vide, lève "IndexError".

random.choices(population, weights=None, *, cum_weights=None, k=1)

   Renvoie une liste de taille *k* d'éléments choisis dans la
   *population* avec remise. Si la *population* est vide, lève
   "IndexError".

   Si une séquence de *poids* est spécifiée, les tirages sont
   effectués en fonction des poids relatifs.  Alternativement, si une
   séquence *cum_weights* est donnée, les tirages sont faits en
   fonction des poids cumulés (peut-être calculés en utilisant
   "itertools.accumulate()").  Par exemple, les poids relatifs "[10,
   5, 30, 5]" sont équivalents aux poids cumulatifs "[10, 15, 45,
   50]".  En interne, les poids relatifs sont convertis en poids
   cumulatifs avant d'effectuer les tirages, ce qui vous permet
   d'économiser du travail en fournissant des pondérations
   cumulatives.

   Si ni *weights* ni *cum_weights* ne sont spécifiés, les tirages
   sont effectués avec une probabilité uniforme.  Si une séquence de
   poids est fournie, elle doit être de la même longueur que la
   séquence *population*.  Spécifier à la fois *weights* et
   *cum_weights* lève une "TypeError".

   Les *weights* ou *cum_weights* peuvent utiliser n'importe quel type
   numérique interopérable avec les valeurs "float" renvoyées par
   "random()" (qui inclut les entiers, les flottants et les fractions
   mais exclut les décimaux).  Les poids sont présumés être non
   négatifs et finis. Une exception "ValueError" est levée si tous les
   poids sont à zéro.

   For a given seed, the "choices()" function with equal weighting
   typically produces a different sequence than repeated calls to
   "choice()".  The algorithm used by "choices()" uses floating-point
   arithmetic for internal consistency and speed.  The algorithm used
   by "choice()" defaults to integer arithmetic with repeated
   selections to avoid small biases from round-off error.

   Ajouté dans la version 3.6.

   Modifié dans la version 3.9: Lève une "ValueError" si tous les
   poids sont à zéro.

random.shuffle(x)

   Mélange la séquence *x* sans créer de nouvelle instance (« sur
   place »).

   Pour mélanger une séquence immuable et renvoyer une nouvelle liste
   mélangée, utilisez "sample(x, k=len(x))" à la place.

   Notez que même pour les petits "len(x)", le nombre total de
   permutations de *x* peut rapidement devenir plus grand que la
   période de la plupart des générateurs de nombres aléatoires. Cela
   implique que la plupart des permutations d'une longue séquence ne
   peuvent jamais être générées.  Par exemple, une séquence de
   longueur 2080 est la plus grande qui puisse tenir dans la période
   du générateur de nombres aléatoires Mersenne Twister.

   Modifié dans la version 3.11: Removed the optional parameter
   *random*.

random.sample(population, k, *, counts=None)

   Return a *k* length list of unique elements chosen from the
   population sequence.  Used for random sampling without replacement.

   Renvoie une nouvelle liste contenant des éléments de la population
   tout en laissant la population originale inchangée.  La liste
   résultante est classée par ordre de sélection de sorte que toutes
   les sous-tranches soient également des échantillons aléatoires
   valides.  Cela permet aux gagnants du tirage (l'échantillon) d'être
   divisés en gagnants du grand prix et en gagnants de la deuxième
   place (les sous-tranches).

   Les membres de la population n'ont pas besoin d'être *hachables* ou
   uniques. Si la population contient des répétitions, alors chaque
   occurrence est un tirage possible dans l'échantillon.

   Les éléments répétés peuvent être spécifiés un à la fois ou avec le
   paramètre optionnel uniquement nommé *counts*.  Par exemple,
   "sample([‘red’, ‘blue’], counts=[4, 2], k=5)" est équivalent à
   "sample([‘red’, ‘red’, ‘red’, ‘red’, ‘blue’, ‘blue’], k=5)".

   Pour choisir un échantillon parmi un intervalle d'entiers, utilisez
   un objet "range()" comme argument.  Ceci est particulièrement
   rapide et économe en mémoire pour un tirage dans une grande
   population : "échantillon(range(10000000), k=60)".

   Si la taille de l'échantillon est supérieure à la taille de la
   population, une "ValueError" est levée.

   Modifié dans la version 3.9: Ajoute le paramètre *counts*.

   Modifié dans la version 3.11: The *population* must be a sequence.
   Automatic conversion of sets to lists is no longer supported.


Discrete distributions
======================

The following function generates a discrete distribution.

random.binomialvariate(n=1, p=0.5)

   Binomial distribution. Return the number of successes for *n*
   independent trials with the probability of success in each trial
   being *p*:

   Mathematically equivalent to:

      sum(random() < p for i in range(n))

   The number of trials *n* should be a non-negative integer. The
   probability of success *p* should be between "0.0 <= p <= 1.0". The
   result is an integer in the range "0 <= X <= n".

   Ajouté dans la version 3.12.


Distributions pour les nombres réels
====================================

Les fonctions suivantes génèrent des distributions spécifiques en
nombre réels. Les paramètres de fonction sont nommés d'après les
variables correspondantes de l'équation de la distribution, telles
qu'elles sont utilisées dans la pratique mathématique courante ; la
plupart de ces équations peuvent être trouvées dans tout document
traitant de statistiques.

random.random()

   Return the next random floating-point number in the range "0.0 <= X
   < 1.0"

random.uniform(a, b)

   Return a random floating-point number *N* such that "a <= N <= b"
   for "a <= b" and "b <= N <= a" for "b < a".

   The end-point value "b" may or may not be included in the range
   depending on floating-point rounding in the expression "a + (b-a) *
   random()".

random.triangular(low, high, mode)

   Return a random floating-point number *N* such that "low <= N <=
   high" and with the specified *mode* between those bounds.  The
   *low* and *high* bounds default to zero and one.  The *mode*
   argument defaults to the midpoint between the bounds, giving a
   symmetric distribution.

random.betavariate(alpha, beta)

   Distribution bêta.  Les conditions sur les paramètres sont "alpha >
   0" et "beta > 0". Les valeurs renvoyées varient entre 0 et 1.

random.expovariate(lambd=1.0)

   Distribution exponentielle.  *lambd* est 1,0 divisé par la moyenne
   désirée.  Ce ne doit pas être zéro.  (Le paramètre aurait dû
   s'appeler "lambda", mais c'est un mot réservé en Python.)  Les
   valeurs renvoyées vont de 0 à plus l'infini positif si *lambd* est
   positif, et de moins l'infini à 0 si *lambd* est négatif.

   Modifié dans la version 3.12: Added the default value for "lambd".

random.gammavariate(alpha, beta)

   Gamma distribution.  (*Not* the gamma function!)  The shape and
   scale parameters, *alpha* and *beta*, must have positive values.
   (Calling conventions vary and some sources define 'beta' as the
   inverse of the scale).

   La fonction de distribution de probabilité est :

                x ** (alpha - 1) * math.exp(-x / beta)
      pdf(x) =  --------------------------------------
                  math.gamma(alpha) * beta ** alpha

random.gauss(mu=0.0, sigma=1.0)

   Normal distribution, also called the Gaussian distribution. *mu* is
   the mean, and *sigma* is the standard deviation.  This is slightly
   faster than the "normalvariate()" function defined below.

   Note sur les fils d’exécution multiples (*Multithreading*) :  quand
   deux fils d’exécution appellent cette fonction simultanément, il
   est possible qu’ils reçoivent la même valeur de retour.  On peut
   l’éviter de 3 façons. 1) Avoir chaque fil utilisant une instance
   différente du générateur de nombres aléatoires. 2) Mettre des
   verrous autour de tous les appels. 3) Utiliser la fonction plus
   lente, mais compatible avec les programmes à fils d’exécution
   multiples, "normalvariate()" à la place.

   Modifié dans la version 3.11: *mu* and *sigma* now have default
   arguments.

random.lognormvariate(mu, sigma)

   Logarithme de la distribution normale.  Si vous prenez le
   logarithme naturel de cette distribution, vous obtiendrez une
   distribution normale avec *mu* moyen et écart-type *sigma*.  *mu*
   peut avoir n'importe quelle valeur et *sigma* doit être supérieur à
   zéro.

random.normalvariate(mu=0.0, sigma=1.0)

   Distribution normale.  *mu* est la moyenne et *sigma* est l'écart
   type.

   Modifié dans la version 3.11: *mu* and *sigma* now have default
   arguments.

random.vonmisesvariate(mu, kappa)

   *mu* est l'angle moyen, exprimé en radians entre 0 et 2**pi*, et
   *kappa* est le paramètre de concentration, qui doit être supérieur
   ou égal à zéro.  Si *kappa* est égal à zéro, cette distribution se
   réduit à un angle aléatoire uniforme sur la plage de 0 à 2**pi*.

random.paretovariate(alpha)

   Distribution de Pareto.  *alpha* est le paramètre de forme.

random.weibullvariate(alpha, beta)

   Distribution de Weibull.  *alpha* est le paramètre de l'échelle et
   *beta* est le paramètre de forme.


Générateur alternatif
=====================

class random.Random([seed])

   Classe qui implémente le générateur de nombres pseudo-aléatoires
   par défaut utilisé par le module "random".

   Modifié dans la version 3.11: Formerly the *seed* could be any
   hashable object.  Now it is limited to: "None", "int", "float",
   "str", "bytes", or "bytearray".

   Subclasses of "Random" should override the following methods if
   they wish to make use of a different basic generator:

   seed(a=None, version=2)

      Override this method in subclasses to customise the "seed()"
      behaviour of "Random" instances.

   getstate()

      Override this method in subclasses to customise the "getstate()"
      behaviour of "Random" instances.

   setstate(state)

      Override this method in subclasses to customise the "setstate()"
      behaviour of "Random" instances.

   random()

      Override this method in subclasses to customise the "random()"
      behaviour of "Random" instances.

   Optionally, a custom generator subclass can also supply the
   following method:

   getrandbits(k)

      Override this method in subclasses to customise the
      "getrandbits()" behaviour of "Random" instances.

class random.SystemRandom([seed])

   Classe qui utilise la fonction "os.urandom()" pour générer des
   nombres aléatoires à partir de sources fournies par le système
   d'exploitation. Non disponible sur tous les systèmes. Ne repose pas
   sur un état purement logiciel et les séquences ne sont pas
   reproductibles. Par conséquent, la méthode "seed()" n'a aucun effet
   et est ignorée. Les méthodes "getstate()" et "setstate()" lèvent
   "NotImplementedError" si vous les appelez.


Remarques sur la reproductibilité
=================================

Sometimes it is useful to be able to reproduce the sequences given by
a pseudo-random number generator.  By reusing a seed value, the same
sequence should be reproducible from run to run as long as multiple
threads are not running.

La plupart des algorithmes et des fonctions de génération de graine du
module aléatoire sont susceptibles d'être modifiés d'une version à
l'autre de Python, mais deux aspects sont garantis de ne pas changer :

* Si une nouvelle méthode de génération de graine est ajoutée, une
  fonction rétro-compatible sera offerte.

* La méthode "random()" du générateur continuera à produire la même
  séquence lorsque la fonction de génération de graine compatible
  recevra la même semence.


Exemples
========

Exemples de base :

   >>> random()                          # Random float:  0.0 <= x < 1.0
   0.37444887175646646

   >>> uniform(2.5, 10.0)                # Random float:  2.5 <= x <= 10.0
   3.1800146073117523

   >>> expovariate(1 / 5)                # Interval between arrivals averaging 5 seconds
   5.148957571865031

   >>> randrange(10)                     # Integer from 0 to 9 inclusive
   7

   >>> randrange(0, 101, 2)              # Even integer from 0 to 100 inclusive
   26

   >>> choice(['win', 'lose', 'draw'])   # Single random element from a sequence
   'draw'

   >>> deck = 'ace two three four'.split()
   >>> shuffle(deck)                     # Shuffle a list
   >>> deck
   ['four', 'two', 'ace', 'three']

   >>> sample([10, 20, 30, 40, 50], k=4) # Four samples without replacement
   [40, 10, 50, 30]

Simulations :

   >>> # Six roulette wheel spins (weighted sampling with replacement)
   >>> choices(['red', 'black', 'green'], [18, 18, 2], k=6)
   ['red', 'green', 'black', 'black', 'red', 'black']

   >>> # Deal 20 cards without replacement from a deck
   >>> # of 52 playing cards, and determine the proportion of cards
   >>> # with a ten-value:  ten, jack, queen, or king.
   >>> deal = sample(['tens', 'low cards'], counts=[16, 36], k=20)
   >>> deal.count('tens') / 20
   0.15

   >>> # Estimate the probability of getting 5 or more heads from 7 spins
   >>> # of a biased coin that settles on heads 60% of the time.
   >>> sum(binomialvariate(n=7, p=0.6) >= 5 for i in range(10_000)) / 10_000
   0.4169

   >>> # Probability of the median of 5 samples being in middle two quartiles
   >>> def trial():
   ...     return 2_500 <= sorted(choices(range(10_000), k=5))[2] < 7_500
   ...
   >>> sum(trial() for i in range(10_000)) / 10_000
   0.7958

Exemple de *bootstrapping* statistique utilisant le ré-échantillonnage
avec remise pour estimer un intervalle de confiance pour la moyenne
d'un échantillon :

   # https://www.thoughtco.com/example-of-bootstrapping-3126155
   from statistics import fmean as mean
   from random import choices

   data = [41, 50, 29, 37, 81, 30, 73, 63, 20, 35, 68, 22, 60, 31, 95]
   means = sorted(mean(choices(data, k=len(data))) for i in range(100))
   print(f'The sample mean of {mean(data):.1f} has a 90% confidence '
         f'interval from {means[5]:.1f} to {means[94]:.1f}')

Exemple d'un *resampling permutation test* pour déterminer la
signification statistique ou valeur p d'une différence observée entre
les effets d'un médicament et ceux d'un placebo :

   # Example from "Statistics is Easy" by Dennis Shasha and Manda Wilson
   from statistics import fmean as mean
   from random import shuffle

   drug = [54, 73, 53, 70, 73, 68, 52, 65, 65]
   placebo = [54, 51, 58, 44, 55, 52, 42, 47, 58, 46]
   observed_diff = mean(drug) - mean(placebo)

   n = 10_000
   count = 0
   combined = drug + placebo
   for i in range(n):
       shuffle(combined)
       new_diff = mean(combined[:len(drug)]) - mean(combined[len(drug):])
       count += (new_diff >= observed_diff)

   print(f'{n} label reshufflings produced only {count} instances with a difference')
   print(f'at least as extreme as the observed difference of {observed_diff:.1f}.')
   print(f'The one-sided p-value of {count / n:.4f} leads us to reject the null')
   print(f'hypothesis that there is no difference between the drug and the placebo.')

Simulation des heures d'arrivée et des livraisons de services pour une
file d'attente de serveurs :

   from heapq import heapify, heapreplace
   from random import expovariate, gauss
   from statistics import mean, quantiles

   average_arrival_interval = 5.6
   average_service_time = 15.0
   stdev_service_time = 3.5
   num_servers = 3

   waits = []
   arrival_time = 0.0
   servers = [0.0] * num_servers  # time when each server becomes available
   heapify(servers)
   for i in range(1_000_000):
       arrival_time += expovariate(1.0 / average_arrival_interval)
       next_server_available = servers[0]
       wait = max(0.0, next_server_available - arrival_time)
       waits.append(wait)
       service_duration = max(0.0, gauss(average_service_time, stdev_service_time))
       service_completed = arrival_time + wait + service_duration
       heapreplace(servers, service_completed)

   print(f'Mean wait: {mean(waits):.1f}   Max wait: {max(waits):.1f}')
   print('Quartiles:', [round(q, 1) for q in quantiles(waits)])

Voir aussi:

  Statistics for Hackers un tutoriel vidéo par Jake Vanderplas sur
  l'analyse statistique en utilisant seulement quelques concepts
  fondamentaux dont la simulation, l'échantillonnage, le brassage et
  la validation croisée.

  Economics Simulation a simulation of a marketplace by Peter Norvig
  that shows effective use of many of the tools and distributions
  provided by this module (gauss, uniform, sample, betavariate,
  choice, triangular, and randrange).

  A Concrete Introduction to Probability (using Python) a tutorial by
  Peter Norvig covering the basics of probability theory, how to write
  simulations, and how to perform data analysis using Python.


Cas pratiques
=============

These recipes show how to efficiently make random selections from the
combinatoric iterators in the "itertools" module:

   def random_product(*args, repeat=1):
       "Random selection from itertools.product(*args, **kwds)"
       pools = [tuple(pool) for pool in args] * repeat
       return tuple(map(random.choice, pools))

   def random_permutation(iterable, r=None):
       "Random selection from itertools.permutations(iterable, r)"
       pool = tuple(iterable)
       r = len(pool) if r is None else r
       return tuple(random.sample(pool, r))

   def random_combination(iterable, r):
       "Random selection from itertools.combinations(iterable, r)"
       pool = tuple(iterable)
       n = len(pool)
       indices = sorted(random.sample(range(n), r))
       return tuple(pool[i] for i in indices)

   def random_combination_with_replacement(iterable, r):
       "Choose r elements with replacement.  Order the result to match the iterable."
       # Result will be in set(itertools.combinations_with_replacement(iterable, r)).
       pool = tuple(iterable)
       n = len(pool)
       indices = sorted(random.choices(range(n), k=r))
       return tuple(pool[i] for i in indices)

Par défaut "random()" renvoie des multiples de 2⁻⁵³ dans la plage *0.0
≤ x < 1.0*.  Tous ces nombres sont uniformément répartis et sont
représentés exactement en tant que nombre à virgule flottante Python.
Cependant, de nombreux autres nombres à virgule flottante dans cette
plage, et représentables en Python, ne sont pas sélectionnables.  Par
exemple "0.05954861408025609" n’est pas un multiple de 2⁻⁵³.

La recette suivante utilise une approche différente.  Tous les nombres
à virgule flottante de l’intervalle sont sélectionnables.  La mantisse
provient d’une distribution uniforme d’entiers dans la plage *2⁵² ≤
mantisse < 2⁵³*.  L’exposant provient d’une distribution géométrique
où les exposants plus petits que *-53* apparaissent moitié moins
souvent que l’exposant suivant juste plus grand.

   from random import Random
   from math import ldexp

   class FullRandom(Random):

       def random(self):
           mantissa = 0x10_0000_0000_0000 | self.getrandbits(52)
           exponent = -53
           x = 0
           while not x:
               x = self.getrandbits(32)
               exponent += x.bit_length() - 32
           return ldexp(mantissa, exponent)

Toutes les real valued distributions dans la classe seront utilisées
dans la nouvelle méthode :

   >>> fr = FullRandom()
   >>> fr.random()
   0.05954861408025609
   >>> fr.expovariate(0.25)
   8.87925541791544

La recette est conceptuellement équivalente à un algorithme qui
choisit parmi tous les multiples de 2⁻¹⁰⁷⁴ dans la plage *0.0 ≤ x <
1.0*.  Tous ces nombres sont uniformément répartis, mais la plupart
doivent être arrondis au nombre à virgule Python inférieur.  (La
valeur 2⁻¹⁰⁷⁴ est le plus petit nombre à virgule flottante positif et
est égal à "math.ulp(0.0)".)

Voir aussi:

  Generating Pseudo-random Floating-Point Values une publication par
  *Allen B. Downey* décrivant des manières de générer des nombres à
  virgule flottante plus fins que normalement générés par "random()".
