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

rand#

Επιστρέφει έναν ψευδοτυχαίο αριθμό κινητής υποδιαστολής στο ημιανοικτό εύρος [0, EXPR).

Η rand αντλεί την επόμενη τιμή από τη ροή ψευδοτυχαίων αριθμών του διερμηνέα και την κλιμακώνει σε 0 <= n < EXPR. Το αποτέλεσμα είναι κανονικός αριθμός Perl (double), ποτέ ακέραιος από μόνος του - περιβάλετε με int όταν θέλετε ακέραιο αριθμό. Το EXPR είναι προαιρετικό και έχει προεπιλογή 1, οπότε η σκέτη rand επιστρέφει float στο [0, 1).

Σύνοψη#

rand EXPR
rand

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

Ένα double-precision float n με 0 <= n < EXPR. Το άνω όριο είναι αποκλειστικό: η rand(6) ποτέ δεν επιστρέφει 6, μόνο τιμές αυστηρά κάτω από αυτό. Για ακέραιο αποτέλεσμα, συνδυάστε με int:

my $die = int(rand(6)) + 1;       # 1..6

Η κατανομή είναι (κατά προσέγγιση) ομοιόμορφη σε όλο το εύρος. Η rand είναι βαθμωτός τελεστής - επιστρέφει μία τιμή ανά κλήση, ανεξάρτητα από το περιβάλλον.

Καθολική κατάσταση που επηρεάζει#

Η rand καταναλώνει την εσωτερική κατάσταση PRNG του διερμηνέα, την οποία μοιράζεται με την srand. Δύο κανόνες απορρέουν από αυτό:

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

  • Κοινόχρηστη ροή: κάθε επόμενη κλήση rand - οπουδήποτε στο πρόγραμμα, σε οποιοδήποτε άρθρωμα - αντλεί από την ίδια ακολουθία. Η κλήση της srand($seed) με σταθερό σπόρο καθιστά αυτή την ακολουθία ντετερμινιστική και αναπαραγώγιμη, κάτι που είναι αυτό που θέλετε για test fixtures και debugging. Η κλήση της srand() χωρίς όρισμα κάνει εκ νέου σπορά από εντροπία.

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

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

Βασική κλήρωση στο [0, 1):

my $u = rand();                   # e.g. 0.4173...

Ρίψη ζαριού - το κανονικό ιδίωμα int(rand(N)) + 1:

my $roll = int(rand(6)) + 1;      # 1..6

Τυχαίο στοιχείο πίνακα:

my @colors = qw(red green blue yellow);
my $pick   = $colors[ rand @colors ];

Η rand @colors χρησιμοποιεί το μήκος του πίνακα (βαθμωτό περιβάλλον επιβαλλόμενο από το πρωτότυπο της rand), οπότε αυτό λειτουργεί για κάθε μέγεθος πίνακα.

Αναπαραγώγιμη ροή - καθορίστε τον σπόρο για τα τεστ:

srand(42);
my @sample = map { rand() } 1..5; # same five numbers every run

Μονόγραμμο ιδίωμα ανακατέματος. Ευανάγνωστο, αλλά με μεροληψία - η sort συγκρίνει ζεύγη παραπάνω από μία φορά, και μια μονομερής rand() ανά σύγκριση δεν παράγει ομοιόμορφη μετάθεση:

my @shuffled = sort { rand() <=> 0.5 } @list;   # biased; do not use

Για δίκαιο ανακάτεμα, χρησιμοποιήστε την List::Util::shuffle:

use List::Util qw(shuffle);
my @shuffled = shuffle @list;

Προσομοίωση ζυγισμένου νομίσματος - σημειώστε ότι το αποκλειστικό άνω όριο σημαίνει ότι το rand() < 0.3 πυροδοτείται με πιθανότητα ακριβώς 0.3:

my $heads = rand() < 0.3 ? "heads" : "tails";

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

  • Το EXPR είναι 0: αντιμετωπίζεται ως 1, οπότε η rand(0) συμπεριφέρεται όπως η rand(1). Αυτή είναι τεκμηριωμένη συμπεριφορά του upstream και διατηρείται εδώ, αλλά είναι ιστορική ιδιορρυθμία - μη βασιστείτε σε αυτήν σε νέο κώδικα.

  • Το EXPR είναι αρνητικό: το αποτέλεσμα είναι απροσδιόριστο στην πράξη - μπορεί να λάβετε 0, μπορεί να λάβετε αρνητικό float, και η συμπεριφορά δεν είναι φορητή μεταξύ εκδόσεων της Perl. Αν θέλετε τιμή στο [-N, 0), γράψτε ρητά rand($n) - $n.

  • Το EXPR είναι undef: μετατρέπεται σε "", αριθμητικοποιείται σε 0, και επομένως συμπεριφέρεται όπως rand(0)rand(1). Υπό use warnings λαμβάνετε προειδοποίηση uninitialized.

  • Το EXPR είναι μη αριθμητικό: ισχύει ο συνηθισμένος εξαναγκασμός βαθμωτού-προς-αριθμό. Η rand("3abc") είναι rand(3) με προειδοποίηση μη αριθμητικού.

  • Δεν είναι κρυπτογραφικά ασφαλής: η rand χρησιμοποιεί γρήγορο PRNG κατάλληλο για προσομοίωση, ανακάτεμα, και test fixtures. Δεν είναι κατάλληλη για tokens συνεδρίας, salts κωδικών, υλικό κλειδιού, ή οποιαδήποτε ευαίσθητη ως προς την ασφάλεια τιμή. Για αυτά, διαβάστε απευθείας από /dev/urandom ή χρησιμοποιήστε Crypt::URandom / Crypt::PRNG.

  • Συμπεριφορά threads/fork: μετά από fork, γονέας και παιδί κληρονομούν την ίδια κατάσταση PRNG και θα παράγουν την ίδια ροή εκτός αν κάποιος από τους δύο καλέσει την srand() για εκ νέου σπορά. Συνηθισμένη παγίδα σε pre-forking διακομιστές - κάντε σπορά στο παιδί.

  • Μεγάλο EXPR: η γεννήτρια παράγει 48 bits τυχαιότητας ανά κλήρωση· για EXPR κοντά ή πάνω από 2**48, η έξοδος δεν κατανέμεται πλέον λεπτομερώς σε όλο το εύρος. Για κρυπτογραφικά πλάτη ούτως ή άλλως δεν θα έπρεπε να χρησιμοποιείτε την rand (δείτε παραπάνω).

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

Πλήρως συμβατό με το upstream Perl 5.42.

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

  • srand - σπορά της PRNG ρητά για αναπαραγωγιμότητα, ή εκ νέου σπορά σε forked παιδί

  • int - αποκόπτει ένα αποτέλεσμα της rand προς το μηδέν για να δώσει ομοιόμορφο ακέραιο στο [0, N)

  • List::Util::shuffle - δίκαιο ανακάτεμα Fisher-Yates· προτιμήστε αυτό αντί του ιδιώματος sort { rand() <=> 0.5 }

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

  • Crypt::PRNG - κρυπτογραφικά ασφαλής PRNG με πλούσιο API όταν χρειάζεστε περισσότερα από ακατέργαστα bytes