Πώς μπορώ να δημιουργήσω τυχαίους ακέραιους αριθμούς μεταξύ δύο καθορισμένων μεταβλητών σε JavaScript, π.χ. x = 4
και y = 8
θα έβγαζε οποιοδήποτε από τα 4, 5, 6, 7, 8
;
Υπάρχουν μερικά παραδείγματα στη σελίδα Mozilla Developer Network:
/**
* Returns a random number between min (inclusive) and max (exclusive)
*/
function getRandomArbitrary(min, max) {
return Math.random() * (max - min) + min;
}
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* The value is no lower than min (or the next integer greater than min
* if min isn't an integer) and no greater than max (or the next integer
* lower than max if max isn't an integer).
* Using Math.round() will give you a non-uniform distribution!
*/
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
<hr>,
Εδώ'είναι η λογική πίσω από αυτό. Είναι ένας απλός κανόνας των τριών:
Η Math.random()
επιστρέφει έναν Αριθμό
μεταξύ 0 (συμπεριλαμβανομένου) και 1 (αποκλειστικού). Έτσι έχουμε ένα διάστημα σαν αυτό:
[0 .................................... 1)
Τώρα, θα θέλαμε έναν αριθμό μεταξύ min
(συμπεριλαμβανομένου) και max
(αποκλειστικού):
[0 .................................... 1)
[min .................................. max)
Μπορούμε να χρησιμοποιήσουμε το Math.random
για να πάρουμε τον αντίστοιχο στο διάστημα [min, max]. Αλλά, πρώτα θα πρέπει να παραγοντοποιήσουμε λίγο το πρόβλημα αφαιρώντας το min
από το δεύτερο διάστημα:
[0 .................................... 1)
[min - min ............................ max - min)
Αυτό μας δίνει:
[0 .................................... 1)
[0 .................................... max - min)
Μπορούμε τώρα να εφαρμόσουμε το Math.random
και στη συνέχεια να υπολογίσουμε το αντίστοιχο. Ας επιλέξουμε έναν τυχαίο αριθμό:
Math.random()
|
[0 .................................... 1)
[0 .................................... max - min)
|
x (what we need)
Έτσι, για να βρούμε το x
, θα κάνουμε:
x = Math.random() * (max - min);
Μην ξεχάσετε να προσθέσετε το min
πίσω, έτσι ώστε να πάρουμε έναν αριθμό στο διάστημα [min, max]:
x = Math.random() * (max - min) + min;
Αυτή ήταν η πρώτη συνάρτηση από το MDN. Η δεύτερη, επιστρέφει έναν ακέραιο αριθμό μεταξύ min
και max
, και τα δύο συμπεριλαμβανομένων.
Τώρα, για να πάρετε ακέραιους αριθμούς, θα μπορούσατε να χρησιμοποιήσετε τις συναρτήσεις round
, ceil
ή floor
.
Θα μπορούσατε να χρησιμοποιήσετε την Math.round(Math.random() * (max - min)) + min
, αυτό όμως δίνει μια μη ομοιόμορφη κατανομή. Τόσο το min
όσο και το max
έχουν μόνο περίπου τη μισή πιθανότητα να ρίξουν:
min...min+0.5...min+1...min+1.5 ... max-0.5....max
└───┬───┘└────────┬───────┘└───── ... ─────┘└───┬──┘ ← Math.round()
min min+1 max
Με την εξαίρεση της max
από το διάστημα, έχει ακόμη λιγότερες πιθανότητες να ρίξει από την min
.
Με Math.floor(Math.random() * (max - min +1)) + min
έχετε μια απόλυτα ομοιόμορφη κατανομή.
min.... min+1... min+2 ... max-1... max.... max+1 (is excluded from interval)
| | | | | |
└───┬───┘└───┬───┘└─── ... ┘└───┬───┘└───┬───┘ ← Math.floor()
min min+1 max-1 max
Δεν μπορείτε'να χρησιμοποιήσετε ceil()
και -1
σε αυτή την εξίσωση επειδή η max
είχε τώρα μια ελαφρώς μικρότερη πιθανότητα να ρίξει, αλλά μπορείτε να ρίξετε και το (ανεπιθύμητο) αποτέλεσμα min-1
.
function getRandomizer(bottom, top) {
return function() {
return Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom;
}
}
χρήση:
var rollDie = getRandomizer( 1, 6 );
var results = ""
for ( var i = 0; i<1000; i++ ) {
results += rollDie() + " "; //make a string filled with 1000 random numbers in the range 1-6.
}
κατανομή:
Επιστρέφουμε μια συνάρτηση (δανειζόμενοι από τον λειτουργικό προγραμματισμό) που όταν καλείται, θα επιστρέφει έναν τυχαίο ακέραιο μεταξύ των τιμών bottom
και top
, συμπεριλαμβανομένων. Λέμε 'inclusive' επειδή θέλουμε να συμπεριλάβουμε και το bottom και το top στο εύρος των αριθμών που μπορούν να επιστραφούν. Με αυτόν τον τρόπο, η getRandomizer( 1, 6 )
θα επιστρέψει είτε το 1, 2, 3, 4, 5, ή 6.
(το κάτω μέρος είναι ο μικρότερος αριθμός, το πάνω μέρος είναι ο μεγαλύτερος αριθμός)
Math.random() * ( 1 + top - bottom )
Η Math.random()
επιστρέφει ένα τυχαίο double μεταξύ 0 και 1, και αν το πολλαπλασιάσουμε με το ένα συν τη διαφορά μεταξύ top
και bottom
, θα πάρουμε ένα double κάπου μεταξύ 0
και 1+b-a
.
Math.floor( Math.random() * ( 1 + top - bottom ) )
Η Math.floor
στρογγυλοποιεί τον αριθμό στον πλησιέστερο ακέραιο. Έτσι έχουμε τώρα όλους τους ακέραιους αριθμούς μεταξύ 0
και top-bottom
. Το 1 φαίνεται μπερδεμένο, αλλά πρέπει να υπάρχει εκεί επειδή στρογγυλοποιούμε πάντα προς τα κάτω, οπότε ο κορυφαίος αριθμός δεν θα επιτευχθεί ποτέ χωρίς αυτό. Ο τυχαίος δεκαδικός αριθμός που δημιουργούμε πρέπει να είναι στο εύρος 0
έως (1+top-bottom)
ώστε να μπορούμε να στρογγυλοποιήσουμε προς τα κάτω και να πάρουμε έναν int στο εύρος 0
έως top-bottom
.
Math.floor( Math.random() * ( 1 + top - bottom ) ) + bottom
Ο κώδικας στο προηγούμενο παράδειγμα μας έδωσε έναν ακέραιο στο εύρος 0
και top-bottom
, οπότε το μόνο που χρειάζεται να κάνουμε τώρα είναι να προσθέσουμε το bottom
σε αυτό το αποτέλεσμα για να πάρουμε έναν ακέραιο στο εύρος bottom
και top
συμπεριλαμβανομένου. :D
ΣΗΜΕΙΩΣΗ: Αν περάσετε πρώτα μια μη ακέραια τιμή ή τον μεγαλύτερο αριθμό θα έχετε ανεπιθύμητη συμπεριφορά, αλλά αν δεν το ζητήσει κανείς δεν πρόκειται να εμβαθύνω στον κώδικα ελέγχου επιχειρημάτων καθώς απέχει αρκετά από την πρόθεση της αρχικής ερώτησης.
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
Για να δοκιμάσετε αυτή τη λειτουργία και παραλλαγές αυτής της λειτουργίας, αποθηκεύστε την παρακάτω HTML/JavaScript σε ένα αρχείο και ανοίξτε την με ένα πρόγραμμα περιήγησης. Ο κώδικας θα παράγει ένα γράφημα που θα δείχνει την κατανομή ενός εκατομμυρίου κλήσεων συναρτήσεων. Ο κώδικας θα καταγράψει επίσης τις ακραίες περιπτώσεις, οπότε αν η συνάρτηση παράγει μια τιμή μεγαλύτερη από τη μέγιστη ή μικρότερη από την ελάχιστη, θα το γνωρίζετε.
<html>
<head>
<script type="text/javascript">
function getRandomInt(lower, upper)
{
//to create an even sample distribution
return Math.floor(lower + (Math.random() * (upper - lower + 1)));
//to produce an uneven sample distribution
//return Math.round(lower + (Math.random() * (upper - lower)));
//to exclude the max value from the possible values
//return Math.floor(lower + (Math.random() * (upper - lower)));
}
var min = -5;
var max = 5;
var array = new Array();
for(var i = 0; i <= (max - min) + 2; i++) {
array.push(0);
}
for(var i = 0; i < 1000000; i++) {
var random = getRandomInt(min, max);
array[random - min + 1]++;
}
var maxSample = 0;
for(var i = 0; i < max - min; i++) {
maxSample = Math.max(maxSample, array[i]);
}
//create a bar graph to show the sample distribution
var maxHeight = 500;
for(var i = 0; i <= (max - min) + 2; i++) {
var sampleHeight = (array[i]/maxSample) * maxHeight;
document.write('<span style="display:inline-block;color:'+(sampleHeight == 0 ? 'black' : 'white')+';background-color:black;height:'+sampleHeight+'px"> [' + (i + min - 1) + ']: '+array[i]+'</span> ');
}
document.write('<hr/>');
</script>
</head>
<body>
</body>
</html>