"random" --- Δημιουργία ψευδοτυχαίων αριθμών
********************************************

**Πηγαίος κώδικας:** Lib/random.py

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

Αυτό το module υλοποιεί ψευδοτυχαίες γεννήτριες αριθμών για διάφορες
κατανομές.

Για ακέραιους, υπάρχει ομοιόμορφη επιλογή από ένα εύρος. Για
ακολουθίες, υπάρχει ομοιόμορφη επιλογή ενός τυχαίου στοιχείου, μια
συνάρτηση για την δημιουργία μιας τυχαίας παραλλαγής μιας λίστας στη
θέση της, και μια συνάρτηση για τυχαία δειγματοληψία χωρίς
αντικατάσταση.

Στην πραγματική γραμμή, υπάρχουν συναρτήσεις για τον υπολογισμό
ομοιόμορφων, κανονικών (Gaussian), lognormal, αρνητικών εκθετικών,
gamma και beta κατανομών. Για τη δημιουργία κατανομών γωνιών,
διατίθεται η κατανομή von Mises.

Σχεδόν όλες οι συναρτήσεις του module εξαρτώνται από τη βασική
συνάρτηση "random()", η οποία παράγει έναν τυχαίο float ομοιόμορφα στο
ημι-ανοιχτό εύρος "0.0 <= X < 1.0". Η Python χρησιμοποιεί το Mersenne
Twister ως βασική γεννήτρια. Παράγει floats με ακρίβεια 53-bit και
έχει περίοδο 2**19937-1. Η υποκείμενη υλοποίηση σε C είναι τόσο
γρήγορη όσο και ασφαλής για νήματα. Το Mersenne Twister είναι μια από
τις πιο εκτενώς δοκιμασμένες γεννήτριες τυχαίων αριθμών που υπάρχουν.
Ωστόσο, είναι εντελώς ντετερμινιστική, δεν είναι κατάλληλη για όλους
τους σκοπούς και είναι εντελώς ακατάλληλη για κρυπτογραφικούς σκοπούς.

Οι συναρτήσεις που παρέχονται από αυτό το module είναι στην
πραγματικότητα δεσμευμένες μέθοδοι ενός κρυφού στιγμιοτύπου της κλάσης
"random.Random". Μπορείτε να δημιουργήσετε τα δικά σας στιγμιότυπα της
"Random" για να λάβετε γεννήτριες που δεν μοιράζονται κατάσταση.

Η κλάση "Random" μπορεί επίσης να υποκλαστεί αν θέλετε να
χρησιμοποιήσετε μια διαφορετική βασική γεννήτρια της δικής σας
επινόησης: δείτε την τεκμηρίωση για αυτή την κλάση για περισσότερες
λεπτομέρειες.

Το module "random" παρέχει επίσης την κλάση "SystemRandom" η οποία
χρησιμοποιεί τη λειτουργία του συστήματος "os.urandom()" για να
δημιουργήσει τυχαίους αριθμούς από πηγές που παρέχονται από το
λειτουργικό σύστημα.

Προειδοποίηση:

  Οι ψευδοτυχαίες γεννήτριες αυτού του module δεν πρέπει να
  χρησιμοποιούνται για σκοπούς ασφαλείας. Για ασφαλείς ή
  κρυπτογραφικούς σκοπούς, δείτε το module "secrets".

Δείτε επίσης:

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

  Complementary-Multiply-with-Carry recipe για μια συμβατή εναλλακτική
  γεννήτρια τυχαίων αριθμών με μεγάλη περίοδο και συγκριτικά απλές
  λειτουργίες ενημέρωσης.

Σημείωση:

  Η παγκόσμια γεννήτρια τυχαίων αριθμών και τα στιγμιότυπα της κλάσης
  "Random" είναι ασφαλή για νήματα. Ωστόσο, στην ελεύθερη κατασκευή
  νημάτων, οι ταυτόχρονες κλήσεις στην παγκόσμια γεννήτρια ή στο ίδιο
  στιγμιότυπο της κλάσης "Random" μπορεί να συναντήσουν ανταγωνισμό
  και κακή απόδοση. Σκεφτείτε να χρησιμοποιήσετε ξεχωριστά στιγμιότυπα
  της κλάσης "Random" ανά νήμα αντίθετα.


Συναρτήσεις καταγραφής
======================

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

   Αρχικοποίηση της γεννήτριας τυχαίων αριθμών.

   Αν το *a* παραλειφθεί ή είναι "None", χρησιμοποιείται η τρέχουσα
   ώρα του συστήματος. Αν οι πηγές τυχαιότητας παρέχονται από το
   λειτουργικό σύστημα, χρησιμοποιούνται αντί της ώρας του συστήματος
   (δείτε τη λειτουργία "os.urandom()" για λεπτομέρειες σχετικά με τη
   διαθεσιμότητα).

   Αν το *a* είναι ακέραιος, χρησιμοποιείται απευθείας.

   Με την έκδοση 2 (η προεπιλεγμένη), ένα αντικείμενο "str", "bytes",
   ή "bytearray" μετατρέπεται σε "int" και χρησιμοποιούνται όλα τα
   bits του.

   Με την έκδοση 1 (παρέχεται για την αναπαραγωγή τυχαίων ακολουθιών
   από παλαιότερες εκδόσεις της Python), ο αλγόριθμος για "str" και
   "bytes" παράγει ένα στενότερο εύρος seeds.

   Άλλαξε στην έκδοση 3.2: Μεταφέρθηκε στο σχήμα έκδοσης 2 που
   χρησιμοποιεί όλα τα bits σε ένα seed τύπου string.

   Άλλαξε στην έκδοση 3.11: Το *seed* πρέπει να είναι ένας από τους
   ακόλουθους τύπους: "None", "int", "float", "str", "bytes", ή
   "bytearray".

random.getstate()

   Επιστρέφει ένα αντικείμενο που καταγράφει την τρέχουσα εσωτερική
   κατάσταση της γεννήτριας. Αυτό το αντικείμενο μπορεί να περαστεί
   στη "setstate()" για να αποκαταστήσει την κατάσταση.

random.setstate(state)

   Το *state* θα πρέπει να έχει αποκτηθεί από μια προηγούμενη κλήση
   στη "getstate()", και η "setstate()" αποκαθιστά την εσωτερική
   κατάσταση της γεννήτριας σε αυτή που ήταν τη στιγμή που κλήθηκε η
   "getstate()".


Συναρτήσεις για bytes
=====================

random.randbytes(n)

   Δημιουργεί *n* τυχαία bytes.

   Αυτή η μέθοδος δεν πρέπει να χρησιμοποιείται για τη δημιουργία
   ασφαλών tokens. Χρησιμοποιήστε αντί αυτού τη
   "secrets.token_bytes()".

   Added in version 3.9.


Συναρτήσεις για ακέραιους
=========================

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

   Επιστρέφει ένα τυχαία επιλεγμένο στοιχείο από "range(start, stop,
   step)".

   Αυτό είναι περίπου ισοδύναμο με το "choice(range(start, stop,
   step))" αλλά υποστηρίζει αυθαίρετα μεγάλα εύρη και είναι
   βελτιστοποιημένο για κοινές περιπτώσεις.

   Το μοτίβο των θέσεων παραμέτρων ταιριάζει με τη συνάρτηση
   "range()".

   Οι παράμετροι λέξεων-κλειδιών δεν πρέπει να χρησιμοποιούνται επειδή
   μπορούν να ερμηνευτούν με απροσδόκητους τρόπους. Για παράδειγμα, το
   "randrange(start=100)" ερμηνεύεται ως "randrange(0, 100, 1)".

   Άλλαξε στην έκδοση 3.2: Η μέθοδος "randrange()" είναι πιο
   εξελιγμένη όσον αφορά την παραγωγή ομοιόμορφα κατανεμημένων τιμών.
   Προηγουμένως χρησιμοποιούσε ένα στυλ όπως "int(random()*n)"  το
   οποίο μπορούσε να παράγει ελαφρώς άνισες κατανομές.

   Άλλαξε στην έκδοση 3.12: Η αυτόματη μετατροπή μη ακέραιων τύπων δεν
   υποστηρίζεται πλέον. Κλήσεις όπως "randrange(10.0)" και
   "randrange(Fraction(10, 1))" τώρα κάνουν raise μια "TypeError".

random.randint(a, b)

   Επιστρέφει έναν τυχαίο ακέραιο *N* τέτοιο ώστε "a <= N <= b".
   Ψευδώνυμο για "randrange(a, b+1)".

random.getrandbits(k)

   Επιστρέφει έναν μη αρνητικό ακέραιο Python με *k* τυχαία bits. Αυτή
   η μέθοδος παρέχεται με την γεννήτρια Mersenne Twister και μερικές
   άλλες γεννήτριες μπορεί επίσης να την παρέχουν ως προαιρετικό μέρος
   του API. Όταν είναι διαθέσιμη, η "getrandbits()" επιτρέπει στην
   "randrange()" να χειρίζεται αυθαίρετα μεγάλα εύρη.

   Άλλαξε στην έκδοση 3.9: Αυτή η μέθοδος τώρα δέχεται το μηδέν για
   *k*.


Συναρτήσεις για ακολουθίες
==========================

random.choice(seq)

   Επιστρέφει ένα τυχαίο στοιχείο από την μη κενή ακολουθία *seq*. Αν
   το *seq* είναι κενό, κάνει raise μια "IndexError".

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

   Επιστρέφει μια λίστα μεγέθους *k* από στοιχεία επιλεγμένα από τον
   *πληθυσμό* με αντικατάσταση. Αν το *population* είναι κενό, κάνει
   raise μια "IndexError".

   Αν μια ακολουθία *weights* καθοριστεί, οι επιλογές γίνονται σύμφωνα
   με τα σχετικά βάρη. Εναλλακτικά, αν μια ακολουθία *cum_weights*
   δοθεί, οι επιλογές γίνονται σύμφωνα με τα σωρευτικά βάρη (ίσως
   υπολογισμένα χρησιμοποιώντας "itertools.accumulate()"). Για
   παράδειγμα, τα σχετικά βάρη "[10, 5, 30, 5]" είναι ισοδύναμα με τα
   σωρευτικά βάρη "[10, 15, 45, 50]". Εσωτερικά, τα σχετικά βάρη
   μετατρέπονται σε σωρευτικά βάρη πριν από τις επιλογές, οπότε η
   παροχή των σωρευτικών βαρών εξοικονομεί εργασία.

   Αν ούτε τα *weights* ούτε τα *cum_weights* καθοριστούν, οι επιλογές
   γίνονται με ίση πιθανότητα. Αν μια ακολουθία βαρών καθοριστεί,
   πρέπει να είναι του ίδιου μήκους με την ακολουθία του *πληθυσμού*.
   Είναι μια "TypeError" να καθορίσετε και τα δύο *weights* και
   *cum_weights*.

   Τα *weights* ή *cum_weights* μπορούν να χρησιμοποιούν οποιονδήποτε
   αριθμητικό τύπο που συνεργάζεται με τις τιμές "float" που
   επιστρέφονται από τη "random()" (αυτό περιλαμβάνει ακέραιους,
   floats και κλάσματα αλλά εξαιρεί τα δεκαδικά). Τα βάρη θεωρούνται
   μη αρνητικά και πεπερασμένα. Μια "ValueError" γίνεται raise αν όλα
   τα βάρη είναι μηδενικά.

   Για ένα δεδομένο seed, η συνάρτηση "choices()" με ίσα βάρη παράγει
   συνήθως μια διαφορετική ακολουθία από τις επαναλαμβανόμενες κλήσεις
   "choice()". Ο αλγόριθμος που χρησιμοποιείται από τη "choices()"
   χρησιμοποιεί αριθμητική κινητής υποδιαστολής για εσωτερική συνέπεια
   και ταχύτητα. Ο αλγόριθμος που χρησιμοποιείται από τη "choice()"
   προεπιλέγει την ακέραια αριθμητική με επαναλαμβανόμενες επιλογές
   για να αποφύγει μικρές προκαταλήψεις από σφάλματα στρογγυλοποίησης.

   Added in version 3.6.

   Άλλαξε στην έκδοση 3.9: Κάνει raise μια "ValueError" αν όλα τα βάρη
   είναι μηδενικά.

random.shuffle(x)

   Ανακατεύει την ακολουθία *x* στη θέση της.

   Για να ανακατέψετε μια αμετάβλητη ακολουθία και να επιστρέψετε μια
   νέα ανακατεμένη λίστα, χρησιμοποιήστε "sample(x, k=len(x))" αντί
   αυτού.

   Σημειώστε ότι ακόμη και για μικρό "len(x)", ο συνολικός αριθμός
   επαναλήψεων του *x* μπορεί να αυξηθεί γρήγορα μεγαλύτερα από την
   περίοδο των περισσότερων γεννητριών τυχαίων αριθμών. Αυτό
   υποδηλώνει ότι οι περισσότερες επαναλήψεις μιας μεγάλης ακολουθίας
   δεν μπορούν ποτέ να παραχθούν. Για παράδειγμα, μια ακολουθία μήκους
   2080 είναι η μεγαλύτερη που μπορεί να χωρέσει εντός της περιόδου
   της γεννήτριας τυχαίων αριθμών του Mersenne Twister.

   Άλλαξε στην έκδοση 3.11: Αφαιρέθηκε η προαιρετική παράμετρος
   *random*.

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

   Επιστρέφει μια λίστα μήκους *k* από μοναδικά στοιχεία επιλεγμένα
   από την ακολουθία του πληθυσμού. Χρησιμοποιείται για τυχαία
   δειγματοληψία χωρίς αντικατάσταση.

   Επιστρέφει μια νέα λίστα που περιέχει στοιχεία από τον πληθυσμό
   αφήνοντας την αρχική ακολουθία του πληθυσμού αμετάβλητη. Η
   προκύπτουσα λίστα είναι σε σειρά επιλογής έτσι ώστε όλα τα
   υπο-κομμάτια να είναι επίσης έγκυρα τυχαία δείγματα. Αυτό επιτρέπει
   στους νικητές της κλήρωσης (το δείγμα) να διαχωριστούν σε νικητές
   του μεγάλου βραβείου και δεύτερης θέσης (τα υπο-κομμάτια).

   Τα μέλη του πληθυσμού δεν χρειάζεται να είναι *hashable* ή
   μοναδικά. Αν ο πληθυσμός περιέχει επαναλήψεις, τότε κάθε εμφάνιση
   είναι μια δυνατή επιλογή στο δείγμα.

   Τα επαναλαμβανόμενα στοιχεία μπορούν να καθοριστούν ένα-ένα ή με
   την προαιρετική παράμετρο μόνο-για-λέξεις-κλειδιά *counts*. Για
   παράδειγμα, "sample(['red', 'blue'], counts=[4, 2], k=5)" είναι
   ισοδύναμο με "sample(['red', 'red', 'red', 'red', 'blue', 'blue'],
   k=5)".

   Για να επιλέξετε ένα δείγμα από ένα εύρος ακέραιων, χρησιμοποιήστε
   ένα "range()" αντικείμενο ως παράμετρο. Αυτό είναι ιδιαίτερα
   γρήγορο και αποδοτικό σε χώρο για δειγματοληψία από έναν μεγάλο
   πληθυσμό: "sample(range(10000000), k=60)".

   Αν το μέγεθος του δείγματος είναι μεγαλύτερο από το μέγεθος του
   πληθυσμού, γίνεται raise μια "ValueError".

   Άλλαξε στην έκδοση 3.9: Προστέθηκε η παράμετρος *counts*.

   Άλλαξε στην έκδοση 3.11: Ο *πληθυσμός* πρέπει να είναι μια
   ακολουθία. Η αυτόματη μετατροπή συνόλων σε λίστες δεν υποστηρίζεται
   πλέον.


Διακριτές κατανομές
===================

Η ακόλουθη συνάρτηση δημιουργεί μια διακριτή κατανομή.

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

   Binomial distribution. Επιστρέφει τον αριθμό των επιτυχιών για *n*
   ανεξάρτητες δοκιμές με την πιθανότητα επιτυχίας σε κάθε δοκιμή να
   είναι *p*:

   Μαθηματικά ισοδύναμο με:

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

   Ο αριθμός των δοκιμών *n* πρέπει να είναι ένας μη αρνητικός
   ακέραιος. Η πιθανότητα επιτυχίας *p* πρέπει να είναι μεταξύ "0.0 <=
   p <= 1.0". Το αποτέλεσμα είναι ένας ακέραιος στο εύρος "0 <= X <=
   n".

   Added in version 3.12.


Πραγματικές κατανομές
=====================

Οι ακόλουθες συναρτήσεις δημιουργούν συγκεκριμένες πραγματικές
κατανομές. Οι παράμετροι των συναρτήσεων ονομάζονται όπως οι
αντίστοιχες μεταβλητές στην εξίσωση της κατανομής, όπως
χρησιμοποιείται στην κοινή μαθηματική πρακτική. Οι περισσότερες από
αυτές τις εξισώσεις μπορούν να βρεθούν σε οποιοδήποτε εγχειρίδιο
στατιστικής.

random.random()

   Επιστρέφει τον επόμενο τυχαίο αριθμό κινητής υποδιαστολής στο εύρος
   "0.0 <= X < 1.0"

random.uniform(a, b)

   Επιστρέφει έναν τυχαίο αριθμό κινητής υποδιαστολής *N* τέτοιο ώστε
   "a <= N <= b" για "a <= b" και "b <= N <= a" για "b < a".

   Η τιμή του τελικού σημείου "b" μπορεί να περιλαμβάνεται ή όχι στο
   εύρος ανάλογα με τη στρογγυλοποίηση κινητής υποδιαστολής στην
   έκφραση "a + (b-a) * random()".

random.triangular(low, high, mode)

   Επιστρέφει έναν τυχαίο αριθμό κινητής υποδιαστολής *N* τέτοιο ώστε
   "low <= N <= high" και με το καθορισμένο *mode* μεταξύ αυτών των
   ορίων. Τα όρια *low* και *high* προεπιλέγονται στο μηδέν και το
   ένα. Η παράμετρος *mode* προεπιλέγεται στο μέσο όρο μεταξύ των
   ορίων, δίνοντας μια συμμετρική κατανομή.

random.betavariate(alpha, beta)

   Κατανομή Beta. Οι συνθήκες για τις παραμέτρους είναι "alpha > 0"
   και "beta > 0". Οι επιστρεφόμενες τιμές κυμαίνονται μεταξύ 0 και 1.

random.expovariate(lambd=1.0)

   Εκθετική κατανομή. Το *lambd* είναι 1.0 διαιρεμένο με τον επιθυμητό
   μέσο όρο. Πρέπει να είναι μη μηδενικό. (Η παράμετρος θα ονομαζόταν
   "lambda", αλλά αυτό είναι μια δεσμευμένη λέξη στην Python.) Οι
   επιστρεφόμενες τιμές κυμαίνονται από 0 έως θετικό άπειρο αν το
   *lambd* είναι θετικό, και από αρνητικό άπειρο έως 0 αν το *lambd*
   είναι αρνητικό.

   Άλλαξε στην έκδοση 3.12: Προστέθηκε η προεπιλεγμένη τιμή για το
   "lambd".

random.gammavariate(alpha, beta)

   Κατανομή Gamma. (*Όχι* η συνάρτηση gamma!) Οι παράμετροι σχήματος
   και κλίμακας, *alpha* και *beta*, πρέπει να έχουν θετικές τιμές.
   (Οι συμβάσεις κλήσης διαφέρουν και μερικές πηγές ορίζουν το 'beta'
   ως το αντίστροφο της κλίμακας).

   Η συνάρτηση κατανομής πιθανότητας είναι:

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

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

   Κανονική κατανομή, επίσης γνωστή ως κατανομή Gaussian. Το *mu*
   είναι ο μέσος όρος, και το *sigma* είναι η τυπική απόκλιση. Αυτό
   είναι ελαφρώς ταχύτερο από τη συνάρτηση "normalvariate()" που
   ορίζεται παρακάτω.

   Σημείωση πολυνημάτωσης: Όταν δύο νήματα καλούν αυτή τη συνάρτηση
   ταυτόχρονα, είναι πιθανό να λάβουν την ίδια τιμή επιστροφής. Αυτό
   μπορεί να αποφευχθεί με τρεις τρόπους. 1) Κάθε νήμα να χρησιμοποιεί
   μια διαφορετική παρουσία της γεννήτριας τυχαίων αριθμών. 2) Να
   τοποθετήσετε κλειδώματα γύρω από όλες τις κλήσεις. 3) Να
   χρησιμοποιήσετε τη πιο αργή, αλλά ασφαλή για νήματα, συνάρτηση
   "normalvariate()" αντί αυτού.

   Άλλαξε στην έκδοση 3.11: Το *mu* και το *sigma* έχουν τώρα
   προεπιλεγμένες παραμέτρους.

random.lognormvariate(mu, sigma)

   Κατανομή log normal. Αν πάρετε τον φυσικό λογάριθμο αυτής της
   κατανομής, θα πάρετε μια κανονική κατανομή με μέσο όρο *mu* και
   τυπική απόκλιση *sigma*. Το *mu* μπορεί να έχει οποιαδήποτε τιμή,
   και το *sigma* πρέπει να είναι μεγαλύτερο από το μηδέν.

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

   Κανονική κατανομή. Το *mu* είναι ο μέσος όρος, και το *sigma* είναι
   η τυπική απόκλιση.

   Άλλαξε στην έκδοση 3.11: Το *mu* και το *sigma* έχουν τώρα
   προεπιλεγμένες παραμέτρους.

random.vonmisesvariate(mu, kappa)

   Το *mu* είναι η μέση γωνία, εκφρασμένη σε ακτίνια μεταξύ 0 και
   2**pi*, και *kappa* είναι η παράμετρος συγκέντρωσης, η οποία πρέπει
   να είναι μεγαλύτερη ή ίση με το μηδέν. Αν το *kappa* είναι ίσο με
   το μηδέν, αυτή η κατανομή μειώνεται σε μια ομοιόμορφη τυχαία γωνία
   στο εύρος 0 έως 2**pi*.

random.paretovariate(alpha)

   Κατανομή Pareto. Το *alpha* είναι η παράμετρος σχήματος.

random.weibullvariate(alpha, beta)

   Κατανομή Weibull. Το *alpha* είναι η παράμετρος κλίμακας και το
   *beta* είναι η παράμετρος σχήματος.


Εναλλακτική Γεννήτρια
=====================

class random.Random([seed])

   Κλάση που υλοποιεί την προεπιλεγμένη γεννήτρια τυχαίων αριθμών που
   χρησιμοποιείται από το "random" module.

   Άλλαξε στην έκδοση 3.11: Προηγουμένως το *seed* μπορούσε να είναι
   οποιοδήποτε hashable αντικείμενο. Τώρα περιορίζεται σε: "None",
   "int", "float", "str", "bytes", ή "bytearray".

   Οι υποκλάσεις της "Random" θα πρέπει να αντικαταστήσουν τις
   παρακάτω μεθόδους αν επιθυμούν να χρησιμοποιήσουν μια διαφορετική
   βασική γεννήτρια:

   seed(a=None, version=2)

      Αντικαταστήστε αυτή τη μέθοδο στις υποκλάσεις για να
      προσαρμόσετε τη "seed()" συμπεριφορά των "Random" στιγμιότυπων.

   getstate()

      Αντικαταστήστε αυτή τη μέθοδο στις υποκλάσεις για να
      προσαρμόσετε τη "getstate()" συμπεριφορά των "Random"
      στιγμιότυπων.

   setstate(state)

      Αντικαταστήστε αυτή τη μέθοδο στις υποκλάσεις για να
      προσαρμόσετε τη "setstate()" συμπεριφορά των "Random"
      στιγμιότυπων.

   random()

      Αντικαταστήστε αυτή τη μέθοδο στις υποκλάσεις για να
      προσαρμόσετε τη "random()" συμπεριφορά των "Random"
      στιγμιότυπων.

   Μια προαιρετική υποκλάση γεννήτριας μπορεί επίσης να παρέχει την
   ακόλουθη μέθοδο:

   getrandbits(k)

      Αντικαταστήστε αυτή τη μέθοδο στις υποκλάσεις για να
      προσαρμόσετε τη "getrandbits()" συμπεριφορά των "Random"
      στιγμιότυπων.

   randbytes(n)

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

class random.SystemRandom([seed])

   Κλάση που χρησιμοποιεί τη συνάρτηση "os.urandom()" για τη
   δημιουργία τυχαίων αριθμών από πηγές που παρέχονται από το
   λειτουργικό σύστημα. Δεν είναι διαθέσιμη σε όλα τα συστήματα. Δεν
   βασίζεται σε λογισμικό κατάσταση, και οι ακολουθίες δεν είναι
   αναπαραγωγίσιμες. Σύμφωνα με αυτό, η μέθοδος "seed()" δεν έχει
   καμία επίδραση και αγνοείται. Οι μέθοδοι "getstate()" και
   "setstate()" προκαλούν "NotImplementedError" αν κληθούν.


Σημειώσεις για την Αναπαραγωγιμότητα
====================================

Μερικές φορές είναι χρήσιμο να είναι δυνατή η αναπαραγωγή των
ακολουθιών που παρέχονται από μια ψευδοτυχαία γεννήτρια αριθμών.
Επαναχρησιμοποιώντας μια τιμή seed, η ίδια ακολουθία θα πρέπει να
είναι αναπαραγωγίσιμη από εκτέλεση σε εκτέλεση, εφόσον δεν τρέχουν
πολλαπλά νήματα ταυτόχρονα.

Οι περισσότεροι αλγόριθμοι και συναρτήσεις σποράς του module random
υπόκεινται σε αλλαγές μεταξύ εκδόσεων της Python, αλλά δύο πτυχές
εγγυώνται ότι δεν θα αλλάξουν:

* Εάν προστεθεί μια νέα μέθοδος σποράς, τότε θα προσφέρεται ένας
  σπορέας συμβατός με παλαιότερες εκδόσεις.

* Η μέθοδος "random()" της γεννήτριας θα συνεχίσει να παράγει την ίδια
  ακολουθία όταν ο συμβατός σπορέας δίνεται την ίδια τιμή seed.


Παραδείγματα
============

Βασικά παραδείγματα:

   >>> 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]

Προσομοιώσεις:

   >>> # 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

Παράδειγμα του *statistical bootstrapping
<https://en.wikipedia.org/wiki/Bootstrapping_(statistics)>*
χρησιμοποιώντας δειγματοληψία με αντικατάσταση για να εκτιμήσει ένα
διάστημα εμπιστοσύνης για τον μέσο όρο ενός δείγματος:

   # 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}')

Παράδειγμα ενός resampling permutation test για να προσδιορίσει τη
στατιστική σημασία ή την p-value μιας παρατηρούμενης διαφοράς μεταξύ
των επιδράσεων ενός φαρμάκου σε σύγκριση με ένα εικονικό φάρμακο:

   # 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.')

Προσομοίωση χρόνων άφιξης και παραδόσεων υπηρεσιών για μια ουρά
πολλαπλών διακομιστών:

   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)])

Δείτε επίσης:

  Statistics for Hackers ένα βίντεο σεμινάριο από τον Jake Vanderplas
  για στατιστική ανάλυση χρησιμοποιώντας μόνο μερικές θεμελιώδεις
  έννοιες όπως η προσομοίωση, η δειγματοληψία, η αναδιάταξη και η
  διασταύρωση επικύρωσης.

  Economics Simulation μια προσομοίωση μιας αγοράς από τον Peter
  Norvig που δείχνει αποτελεσματική χρήση πολλών από τα εργαλεία και
  τις κατανομές που παρέχονται από αυτό το module (gauss, uniform,
  sample, betavariate, choice, triangular, και randrange).

  A Concrete Introduction to Probability (using Python) ένα σεμινάριο
  από τον Peter Norvig που καλύπτει τα βασικά της θεωρίας πιθανοτήτων,
  πώς να γράψετε προσομοιώσεις, και πώς να εκτελέσετε ανάλυση
  δεδομένων χρησιμοποιώντας Python.


Συνταγές
========

Αυτές οι συνταγές δείχνουν πώς να κάνετε αποτελεσματικές τυχαίες
επιλογές από τους συνδυαστικούς επαναληπτές στο module "itertools" :

   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)

Η προεπιλεγμένη "random()" επιστρέφει πολλαπλάσια του 2⁻⁵³ στο
διάστημα *0.0 ≤ x < 1.0*. Όλοι αυτοί οι αριθμοί είναι ομοιόμορφα
κατανεμημένοι και είναι ακριβώς αναπαραστάσιμοι ως Python floats.
Ωστόσο, πολλά άλλα αναπαραστάσιμα floats σε αυτό το διάστημα δεν είναι
δυνατές επιλογές. Για παράδειγμα, "0.05954861408025609" δεν είναι
πολλαπλάσιο του 2⁻⁵³.

Η παρακάτω συνταγή ακολουθεί μια διαφορετική προσέγγιση. Όλα τα floats
στο διάστημα είναι δυνατές επιλογές. Η mantissa προέρχεται από μια
ομοιόμορφη κατανομή ακεραίων στο διάστημα *2⁵² ≤ mantissa < 2⁵³*. Ο
εκθέτης προέρχεται από μια γεωμετρική κατανομή όπου οι εκθέτες
μικρότεροι από *−53* εμφανίζονται μισή φορά συχνότερα από τον επόμενο
μεγαλύτερο εκθέτη.

   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)

Όλες οι πραγματικές κατανομές στην κλάση θα χρησιμοποιούν τη νέα
μέθοδο:

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

Η συνταγή είναι εννοιολογικά ισοδύναμη με έναν αλγόριθμο που επιλέγει
από όλα τα πολλαπλάσια του 2⁻¹⁰⁷⁴ στο διάστημα *0.0 ≤ x < 1.0*. Όλοι
αυτοί οι αριθμοί είναι ομοιόμορφα κατανεμημένοι, αλλά οι περισσότεροι
πρέπει να στρογγυλοποιηθούν προς τα κάτω στο πλησιέστερο
αναπαραστάσιμο Python float. (Η τιμή 2⁻¹⁰⁷⁴ είναι το μικρότερο θετικό
μη κανονικοποιημένο float και ισούται με "math.ulp(0.0)".)

Δείτε επίσης:

  Generating Pseudo-random Floating-Point Values ένα άρθρο του Allen
  B. Downey που περιγράφει τρόπους δημιουργίας πιο λεπτομερών floats
  από ό,τι παράγονται συνήθως από "random()".


Χρήση από τη γραμμή εντολών
===========================

Added in version 3.13.

Το module "random" μπορεί να εκτελεστεί από τη γραμμή εντολών.

   python -m random [-h] [-c CHOICE [CHOICE ...] | -i N | -f N] [input ...]

Αποδέχεται τις παρακάτω επιλογές:

-h, --help

   Εμφανίζει το μήνυμα βοήθειας και εξέρχεται.

-c CHOICE [CHOICE ...]
--choice CHOICE [CHOICE ...]

   Εκτυπώνει μια τυχαία επιλογή, χρησιμοποιώντας τη "choice()".

-i <N>
--integer <N>

   Εκτυπώνει έναν τυχαίο ακέραιο μεταξύ 1 και N συμπεριλαμβανομένου,
   χρησιμοποιώντας τη "randint()".

-f <N>
--float <N>

   Εκτυπώνει έναν τυχαίο αριθμό κινητής υποδιαστολής μεταξύ 0 και N
   συμπεριλαμβανομένου, χρησιμοποιώντας τη "uniform()".

Εάν δεν δοθούν επιλογές, η έξοδος εξαρτάται από την είσοδο:

* Συμβολοσειρά ή πολλαπλά: ίδια με την "--choice".

* Ακέραιος: ίδια με την "--integer".

* Αριθμός κινητής υποδιαστολής: ίδια με την "--float".


Παράδειγμα από τη γραμμή εντολών
================================

Εδώ είναι μερικά παραδείγματα της διεπαφής γραμμής εντολών του
"random":

   $ # Choose one at random
   $ python -m random egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce"
   Lobster Thermidor aux crevettes with a Mornay sauce

   $ # Random integer
   $ python -m random 6
   6

   $ # Random floating-point number
   $ python -m random 1.8
   1.7080016272295635

   $ # With explicit arguments
   $ python  -m random --choice egg bacon sausage spam "Lobster Thermidor aux crevettes with a Mornay sauce"
   egg

   $ python -m random --integer 6
   3

   $ python -m random --float 1.8
   1.5666339105010318

   $ python -m random --integer 6
   5

   $ python -m random --float 6
   3.1942323316565915
