Αριθμητικές συναρτήσεις

srand#

Σπείρει τη γεννήτρια ψευδοτυχαίων αριθμών.

Η srand θέτει την εσωτερική κατάσταση της PRNG από την οποία αντλεί η rand. Καλέστε την με ρητό ακέραιο για να λάβετε αναπαραγώγιμη ροή, ή καλέστε την χωρίς όρισμα για να ξανασπείρετε από την καλύτερη πηγή εντροπίας που προσφέρει η πλατφόρμα. Από την Perl 5.14 και μετά η srand επιστρέφει τον σπόρο που χρησιμοποίησε, ώστε να μπορείτε να τον καταγράψετε και να αναπαραγάγετε την ίδια εκτέλεση αργότερα.

Σύνοψη#

srand EXPR
srand

Τι επιστρέφεται#

Ο σπόρος που εγκαταστάθηκε, ως ακέραιος. Για srand($n) η τιμή επιστροφής είναι το $n (μετά τη συνήθη αποκοπή σε ακέραιο). Για srand() χωρίς όρισμα η τιμή επιστροφής είναι ο αυτόματα επιλεγμένος σπόρος που αντλείται από την εντροπία του συστήματος - αποτυπώστε την αν ποτέ θέλετε να αναπαραγάγετε την εκτέλεση.

my $seed = srand();                 # auto-seed, remember what we used
warn "seed for this run: $seed\n";

Πριν την Perl 5.14 η srand δεν επέστρεφε τίποτα χρήσιμο. Κώδικας που βασίζεται στην επιστροφή του σπόρου θα πρέπει να δηλώνει την ελάχιστη έκδοση:

use v5.14;                          # so srand returns the seed

Καθολική κατάσταση#

Η srand μεταλλάσσει μια μοναδική PRNG καθολική σε επίπεδο διεργασίας. Κάθε επόμενη κλήση στην rand στην ίδια διεργασία - από οποιοδήποτε πακέτο, οποιοδήποτε άρθρωμα, οποιοδήποτε περιβάλλον χωρίς threads - διαβάζει από αυτήν τη μοναδική κατάσταση. Δεν υπάρχει RNG ανά πακέτο ή ανά εμβέλεια. Συνέπειες:

  • Η κλήση srand($k) οπουδήποτε στο πρόγραμμα επηρεάζει κάθε μεταγενέστερη κλήση rand, συμπεριλαμβανομένων εκείνων μέσα σε αρθρώματα που δεν έχετε γράψει εσείς.

  • Δύο διεργασίες που καλούν srand($k) με το ίδιο $k παράγουν πανομοιότυπες ροές rand. Αυτή είναι η βάση των αναπαραγώγιμων δοκιμών και ο λόγος που πρέπει να ξανασπείρετε μετά από fork.

  • Αν η srand δεν κληθεί ποτέ ρητά, καλείται σιωπηρά χωρίς όρισμα την πρώτη φορά που καλείται η rand.

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

Αναπαραγώγιμη περίπτωση δοκιμής με ρητό σπόρο - ίδια είσοδος, ίδια ακολουθία, κάθε εκτέλεση:

srand(42);
my @sample = map { rand() } 1..5;   # identical on every invocation

Σπορά από time() για τυχαιότητα με σπάνιες συγκρούσεις σε ξεχωριστές εκτελέσεις που ξεκίνησαν σε διαφορετικά δευτερόλεπτα πραγματικού χρόνου. Αυτό είναι το κλασικό μοτίβο· δεν είναι κρυπτογραφικού επιπέδου:

srand(time() ^ $$);                 # time XOR pid, old-school spread

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

my $seed = srand();                 # auto-seed, capture it
eval { run_randomised_tests() };
if ($@) {
    warn "FAILED with seed=$seed - reproduce with: srand($seed)\n";
    die $@;
}

Ξανασπείρετε μετά από fork ώστε γονέας και παιδί να μη μοιράζονται ροή:

my $pid = fork();
die "fork: $!" unless defined $pid;
if ($pid == 0) {
    srand();                        # child gets fresh entropy
    exec_child_work();
}

Δύο ανεξάρτητες ροές από τον ίδιο σπόρο - χρήσιμο όταν θέλετε να κάνετε checkpoint και να συνεχίσετε, ή να συγκρίνετε δύο εκτελέσεις που απέκλιναν μετά από ένα σημείο απόφασης:

srand(12345);
my @first  = map { rand() } 1..10;

srand(12345);
my @second = map { rand() } 1..10;  # identical to @first

Οριακές περιπτώσεις#

  • Η μορφή χωρίς όρισμα κάνει αυτόματη σπορά με την καλύτερη διαθέσιμη εντροπία. Σε Linux αυτή αντλείται από το /dev/urandom (ή την getrandom(2)). Ο σπόρος είναι αρκετά ευρύς ώστε να τον αντιμετωπίζετε ως αδιαφανή, όχι ως μικρό ακέραιο.

  • Μην καλείτε την srand() χωρίς ορίσματα περισσότερες από μία φορά ανά διεργασία. Η εσωτερική κατάσταση της PRNG ήδη φέρει περισσότερη εντροπία από αυτή που μπορεί να επαναφέρει οποιοσδήποτε μεμονωμένος σπόρος, οπότε η εκ νέου σπορά χάνει τυχαιότητα αντί να την προσθέτει. Οι δύο νόμιμοι λόγοι να την καλείτε επανειλημμένα είναι (α) με ρητό σπόρο για αναπαραγωγιμότητα, και (β) μία φορά σε κάθε παιδί μετά από fork.

  • Τα δεκαδικά ορίσματα αποκόπτονται σιωπηρά σε ακέραιο. Οι srand(42) και srand(42.9) εγκαθιστούν τον ίδιο σπόρο. Πάντα περνάτε ακέραιο ώστε η πρόθεση να είναι προφανής.

  • Ίδιος σπόρος ⇒ πανομοιότυπη ροή rand. Αυτό είναι όλο το νόημα για τις δοκιμές· αυτό είναι όλο το πρόβλημα για την ασφάλεια.

  • Όχι κρυπτογραφικά ασφαλές. Οι rand/srand χρησιμοποιούν γρήγορη μη κρυπτογραφική PRNG. Μην τις χρησιμοποιείτε για να παράγετε tokens συνεδρίας, nonces, κλειδιά, salts κωδικών πρόσβασης, ή οτιδήποτε δεν πρέπει να μπορεί να προβλέψει ένας αντίπαλος. Χρησιμοποιήστε [Crypt::URandom][cu] ή διαβάστε απευθείας από το /dev/urandom.

  • Μεταβλητή περιβάλλοντος PERL_RAND_SEED. Αν τεθεί σε μη αρνητικό ακέραιο κατά την εκκίνηση της διεργασίας, η srand() χωρίς όρισμα (συμπεριλαμβανομένης της σιωπηρής κλήσης που πυροδοτείται από την πρώτη rand) εγκαθιστά ντετερμινιστικό σπόρο που παράγεται από αυτή την τιμή. Η παραγωγή είναι σκόπιμα απροσδιόριστη· εγγυάται μόνο η αναπαραγωγιμότητα ίδια-τιμή-ίδιο-δυαδικό-ίδιος-κώδικας. Προορίζεται για αποσφαλμάτωση και ανάλυση επιδόσεων. Η μεταβλητή διαβάζεται μία φορά κατά την εκκίνηση· η μετάλλαξη του %ENV αργότερα δεν έχει επίδραση στην τρέχουσα διεργασία.

  • Threads (use threads): κάθε κλώνος διερμηνέα λαμβάνει τη δική του κατάσταση PRNG. Η σπορά σε ένα thread δεν επηρεάζει άλλο.

  • Εμβέλεια του σπόρου: δεν υπάρχει τρόπος να local-οποιήσετε την κατάσταση της PRNG. Αν μια βιβλιοθήκη που καλείτε ενδιάμεσα εκτελέσει srand, η ροή σας διαταράσσεται. Αποτυπώστε και επαναφέρετε χειροκίνητα αν αυτό έχει σημασία.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42. Το PERL_RAND_SEED τιμάται με την ίδια σύμβαση «σκόπιμα απροσδιόριστο αλλά αναπαραγώγιμο» όπως στην perl5.

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

  • rand - ο καταναλωτής της κατάστασης που εγκαθιστά η srand· αντλεί την επόμενη τιμή από τη σπαρμένη ροή

  • time - δευτερόλεπτα από την epoch· η κλασική πρόχειρη πηγή σπόρου για κώδικα μη σχετιζόμενο με ασφάλεια (srand(time() ^ $$))

  • [Crypt::URandom][cu] - κρυπτογραφικά ασφαλή τυχαία bytes από την δεξαμενή εντροπίας του OS· χρησιμοποιήστε αυτό, όχι το rand, για tokens και κλειδιά

  • [Math::Random::MT][mt] - Mersenne Twister PRNG με τη δική του ανεξάρτητη κατάσταση, όταν χρειάζεστε δεύτερη ροή που δεν διαταράσσεται από κλήσεις βιβλιοθήκης προς το rand

  • perlrun - τεκμηριώνει τη μεταβλητή περιβάλλοντος PERL_RAND_SEED και άλλα κουμπιά εκκίνησης