I am making a simple exercise in JavaScript in which I have to generate a random number between 1 and 3 in JavaScript and found this:
return Math.floor(Math.random() * (max - min + 1) + min);
But with a friend we figured out that we can use Math.round instead for the same purpose:
return Math.round(Math.random() * (max - min) + min);
What caught our attention is that the last formula is not being suggested anywhere on Internet (as far as we were able to search for it...).
Are there any explanation about why this is not used?
We have tried to confirm why return Math.round(Math.random() * (max - min) + min); is not being suggested for the use of generating random numbers instead/or as an alternative to return Math.round(Math.random() * (max - min) + min);
We can run a simple experiment to see why using Math.round will not give the results you want. We'll run each function 100,000 times and count how many of each result we get.
When using Math.floor, you can see that the distribution of all the items is approximately equal (~20,000 here)
let min = 0;
let max = 5;
let counts = [];
for (let i = 0; i < 100_000; i++) {
const index = Math.floor(Math.random() * (max - min) + min);
if (!counts[index]) counts[index] = 0;
counts[index]++;
}
console.log(counts);
But with Math.round, the first and last values will have around half the values of the others. This is because part of the values that should be going to them are being rounded into the other values.
let min = 0;
let max = 5;
let counts = [];
for (let i = 0; i < 100_000; i++) {
const index = Math.round(Math.random() * (max - min) + min);
if (!counts[index]) counts[index] = 0;
counts[index]++;
}
console.log(counts);
I need array with random non repeating values. I find solving with includes() but i want make without it.
CODE
function rand(min, max){
return Math.round( Math.random() * (max - min) + min);
}
function getRandArray(n, min, max) {
//n - array length
var randArr = [];
randArr[0] = rand(min, max);
for (var i = 0; i < n; i++) {
var randNum = rand(min, max);
for (var j = 0; j < randArr.length; j++){
if (randNum != randArr[j])
randArr[i] = randNum;
else
randNum = rand(min, max);
}
}
return randArr;
}
You can leverage the power of the ES6 Set to do this very easily. Since you are looking for an array output, you can simply use Array.from and pass in the set to return from the function. Here's what it would look like:
function rand(min, max){
return Math.round( Math.random() * (max - min) + min);
}
function getRandArr(n, min, max) {
var set = new Set();
// ensure that the number of unique numbers they want is possible
var maxNumsInArr = Math.min(n, max-min+1);
while(set.size < maxNumsInArr) {
set.add(rand(min, max));
}
return Array.from(set);
}
console.log(getRandArr(10, 0, 10));
console.log(getRandArr(5, 100, 399));
console.log(getRandArr(5, 0, 2)); // only 3 possible unique values, so length will be 3
If ES6 is not an option you can convert the random numbers into String keys for an object and take advantage of the fact that an object will not allow duplicate properties like this:
function rand(min, max){
return Math.round( Math.random() * (max - min) + min);
}
function getRandArr(n, min, max) {
if (n > (max - min + 1)) {
throw "Cannot create array of size " + n;
}
var res = {};
while (Object.keys(res).length < n) {
var r = rand(min, max);
res[r] = true;
}
var array = Object.keys(res);
return array;
}
console.log(getRandArr(100, 0, 10000));
You could always convert the array of Strings back to numbers with a single pass after you have the results.
Adding a property to an object will use a hash of the property name so you get O(1) time for checking if the number is unique.
I want to generate a random number between 1 and 10 up to 2 decimal places,
I'm currently using this below to generate my numbers,
var randomnum = Math.floor(Math.random() * (10.00 - 1.00 + 1.00)) + 1.00;
Ultimately, I would like to know how to generate numbers like:
1.66
5.86
8.34
In the format: var randomnum = then the code
sidenote: I don't remember why I previously had generated my numbers like that but remember something about Math.random generating numbers to 8 decimal places.
Thank you for the help! :)
Ps: I've seen a lot of posts about waiting to round down or up generated numbers and haven't found one wanting to generate them straight out.
UPDATE: I want a number value not a string that looks like a number
You were very close, what you need is not to work with decimal numbers as min and max. Let's have max = 1000 and min = 100, so after your Math.floor you will need to divide by 100:
var randomnum = Math.floor(Math.random() * (1000 - 100) + 100) / 100;
Or if you want to work with decimals:
var precision = 100; // 2 decimals
var randomnum = Math.floor(Math.random() * (10 * precision - 1 * precision) + 1 * precision) / (1*precision);
Multiply the original random number by 10^decimalPlaces, floor it, and then divide by 10^decimalPlaces. For instance:
floor(8.885729840652472 * 100) / 100 // 8.88
function genRand(min, max, decimalPlaces) {
var rand = Math.random()*(max-min) + min;
var power = Math.pow(10, decimalPlaces);
return Math.floor(rand*power) / power;
}
for (var i=0; i<20; i++) {
document.write(genRand(0, 10, 2) + "<br>");
}
Edit in response to comments:
For an inclusive floating-point random function (using this answer):
function genRand(min, max, decimalPlaces) {
var rand = Math.random() < 0.5 ? ((1-Math.random()) * (max-min) + min) : (Math.random() * (max-min) + min); // could be min or max or anything in between
var power = Math.pow(10, decimalPlaces);
return Math.floor(rand*power) / power;
}
Just to simplify things visually, mathematically and functionally based on the examples above.
function randomNumberGenerator(min = 0, max = 1, fractionDigits = 0, inclusive = true) {
const precision = Math.pow(10, Math.max(fractionDigits, 0));
const scaledMax = max * precision;
const scaledMin = min * precision;
const offset = inclusive ? 1 : 0;
const num = Math.floor(Math.random() * (scaledMax - scaledMin + offset)) + scaledMin;
return num / precision;
};
The Math.max protects against negative decimal places from fractionDigits
You can use below code.
var randomnum = (Math.random() * (10.00 - 1.00 + 1.00) + 1.00).toFixed(2);
A more way with typescript/angular example:
getRandom(min: number, max: number) {
return Math.random() * (max - min) + min;
}
console.log('inserting min and max values: ', this.getRandom(-10.0, -10.9).toPrecision(4));
getting random values between -10.0 and -10.9
Here is another way not yet mentioned, which will generate a random number between 1 and 9.99...
(Math.random() * 8 + 1 + Math.random()).toFixed(2)
console.log((Math.random() * 8 + 1 + Math.random()).toFixed(2))
Whether this is the most practical approach is another question altogether.
A simple javascript example to generate a random number with precision:
function genRand(min, max, decimalPlaces) {
return (Math.random() * (max - min) + min).toFixed(decimalPlaces) * 1;
}
console.log(genRand(-5, 5, 2));
I'm generating random numbers from 1 to 20 by calling generateRandom(). How can I exclude some values, say 8 and 15?
function generateRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var test = generateRandom(1, 20)
it should be or instead of and
function generateRandom(min, max) {
var num = Math.floor(Math.random() * (max - min + 1)) + min;
return (num === 8 || num === 15) ? generateRandom(min, max) : num;
}
var test = generateRandom(1, 20)
One way, which will maintain the generator's statistical properties, is to generate a number in [1, 18]. Then apply, in this order:
If the number is 8 or more, add 1.
If the number is 15 or more, add 1.
I'd be reluctant to reject and re-sample as that can cause correlation plains to appear in linear congruential generators.
Right now I'm using this and it works without causing browser issues with infinities loops, also tested in mobile devices (using Ionic/Cordova):
function getRandomIndex(usedIndexs, maxIndex) {
var result = 0;
var min = 0;
var max = maxIndex - 1;
var index = Math.floor(Math.random()*(max-min+1)+min);
while(usedIndexs.indexOf(index) > -1) {
if (index < max) {
index++;
} else {
index = 0;
}
}
return index;
}
To generate random number between 1 and 20 excluding some given numbers, you can simply do this:
function generateRandom(min, max, exclude) {
let random;
while (!random) {
const x = Math.floor(Math.random() * (max - min + 1)) + min;
if (exclude.indexOf(x) === -1) random = x;
}
return random;
}
const test = generateRandom(1, 20, [8, 15]);
/**
* Returns a random integer between min (inclusive) and max (inclusive).
* Pass all values as an array, as 3rd argument which values shouldn't be generated by the function.
* 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) {
const minimum = Math.ceil(min);
const maximum = Math.floor(max);
return Math.floor(Math.random() * (maximum - minimum + 1)) + minimum;
}
function getRandomIntExcludingExistingNumbers(min, max, excludeArrayNumbers) {
let randomNumber;
if(!Array.isArray(excludeArrayNumbers)) {
randomNumber = getRandomInt(min, max);
return randomNumber;
}
do {
randomNumber = getRandomInt(min, max);
} while ((excludeArrayNumbers || []).includes(randomNumber));
return randomNumber;
}
const randomNumber = getRandomIntExcludingExistingNumbers(1, 10, [1, 2, 4, 5, 9]);
// It will return random integer between 1 to 10 excluding 1,2,4,5,9
Explanation:
getRandomInt function generates random numbers between min and max values.
I am utilizing that function to make "getRandomIntExcludingExistingNumbers" function to avoid specific values.
we will simply call getRandomInt(min, max) values.
Then in do while loop we will check if randomly generated values belongs to any of the values which shouldn't be generated.
If it is unique integer outside exclude values then we will return the value.
If our value is from the excluded values, then from do -- while loop, we will once again call getRandomInt to generate new values.
Here is a slightly modified answer that is similar to all the others but it allows your to pass a single or an array of failing numbers
function generateRandom(min, max, failOn) {
failOn = Array.isArray(failOn) ? failOn : [failOn]
var num = Math.floor(Math.random() * (max - min + 1)) + min;
return failOn.includes(num) ? generateRandom(min, max, failOn) : num;
}
You could make use of a recursive function
function generateRandom(min, max, num1, num2) {
var rtn = Math.floor(Math.random() * (max - min + 1)) + min;
return rtn == num1 || rtn == num2 ? generateRandom(min, max, num1, num2) : rtn;
}
I think it should be like this, if you want good distribution on all numbers.
and, for this solution, it is required to higher max than 15 and lower min that 8
function generateRandom(min, max) {
var v = Math.floor(Math.random() * (max - min + 1 - 2)) + min;
if (v == 8) return max-1;
else if (v == 15) return max-2;
else return v;
}
var test = generateRandom(1, 20)
You can build an array dynamically. Depending on where you are getting the excluded numbers. Something like:
var excluded = [8, 15];
var random = [];
for(var i = min; i <= max; i++) {
if(excluded.indexOf(i) !== -1) {
random.push(i);
}
}
Then use the tips found in the answer for this post: How can I generate a random number within a range but exclude some?. Should get you to where you want to go.
Here is a really stupidly overcomplicated solution...
<script>
var excludedNumbers = [];
excludedNumbers.push(8);
excludedNumbers.push(15);
excludedNumbers.push(10);
var array = generateExclude(excludedNumbers, 1, 20);
function generateExclude(excludedNumbers, min, max){
var newNumbers = [];
for(var i = min; i <= max; i++) {
for(var j = 0; j < excludedNumbers.length; j++) {
var checker = $.inArray(i, excludedNumbers)
if(checker > -1){
}else{
if($.inArray(i, newNumbers)<= -1){
newNumbers.push(i);
}
}
};
};
return newNumbers;
}
function generateRandomNumbers(items){
var num = items[Math.floor(Math.random()*items.length)];;
return num;
}
console.log(generateRandomNumbers(array))
</script>
I have answered a similar question for Java: Generate random numbers except certain values. I just copy and paste the answer as follows.
Actually, we do not need to use contains(random) with a while loop.
To simplify the question, let's see what happens if we only have one excluding value. We can split the result to 2 parts. Then the number of possible values is range-1. If the random number is less than the excluded value, just return it. Otherwise, we could add 1.
For multiple excluding values, We can split the result set into size+1 parts, where size means the number of excluding values. Then the number of possible values is range-size. Then we sort excluding values in ascending order. If random number is less than the excluding value minus i, then we just return the random number add i, where i is the index of the the excluding value.
public int generateRandomNumberWithExcepts(int start, int end, List<Integer> excepts) {
int size = excepts.size();
int range = end - start + 1 - size;
int randNum = random.nextInt(range) + start;
excepts.sort(null); // sort excluding values in ascending order
int i=0;
for(int except : excepts) {
if(randNum < except-i){
return randNum + i;
}
i++;
}
return randNum + i;
}
I've read through all these answers and they differ a lot in philosophy, so I thought I might add my very own 2 bits, despite of this question having an answer, because I do think there is a better and more elegant way of approaching this problem.
We can make a function that takes min, max and blacklist as parameters and outputs a random result without using recursion (and with close to 0 if statements):
const blrand = function(min, max, blacklist) {
if(!blacklist)
blacklist = []
let rand = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
let retv = 0;
while(blacklist.indexOf(retv = rand(min,max)) > -1) { }
return retv;
}
usage:
let randomNumber = blrand(0, 20, [8, 15]);
You can simply do like this
function generatedRandExclude(showed,max) {
let randNo = -1;
while(showed.length < max) {
randNo = Math.floor(Math.random() * Math.floor(max));
if(!showed.includes(randNo)) {
showed.push(randNo);
break;
}
}
return randNo;
}
let showed = [];
function run() {
console.log(generatedRandExclude(showed,6));
}
run();
run();
run();
run();
generatedRandExclude generate random number excluded using array showed.
This is a simple and neat idea, I am a electromechanical engineer and I am just learning JS.
This is going to print a random numeber between 1 and 100.
Except 8 and 15
var r; // this is the random integer.
var val; //this will serve as validator for the random integer.
val=0;
while(val==0) {
r=Math.round(Math.random()*100)+1;
if(r!=8 && r!=15){val=1;} //a valid number will be any number different from 8 and 15
//then validator will change and go out from the loop.
}
document.write(r);
You could take an offset for random values greater or equal than zerow ith a sorted (ascending) array and return a sum with adjusted random value.
const
getRandomWithoutZero = (lower, upper, gaps) => () => {
const r = Math.floor(Math.random() * (upper - lower + 1 - gaps.length) + lower);
return gaps.reduce((s, g) => s + (s >= g), r);
},
random = getRandomWithoutZero(-9, 9, [-3, 0, 4]),
count = {};
for (let i = 0; i < 1.6e6; i++) {
const r = random();
count[r] = (count[r] || 0) + 1;
}
console.log(count);
.as-console-wrapper { max-height: 100% !important; top: 0; }
How can I generate a random number between 1 - 10 except that the random number can't be 3
Get a random number between 1 and 9 and then add one if it's 3 or greater, or
better, just change any 3s into 10s.
function getNumber() {
return (n = 9 * Math.ceil(Math.random())) === 3? 10: n;
}
Based on this nice answer:
function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var rand;
while((rand = getRandomInt(1, 10)) == 3);
// rand is now your random number
function rand(begin, end) {
var result = Math.floor( Math.random() * (end - begin + 1) ) + begin;
return result === 3 ? rand(begin, end) : result;
}
function rand(){
var r = Math.ceil(Math.random() * 10);
if (r==3){
return rand()}
else
return r;
}
Here's a short, quick solution, using a self-executing function, that does what you need exactly but is only useful for the specific circumstance you describe:
var randOneToTenButNotThree = function () {
var result = Math.floor(Math.random() * 10) + 1; // PICK A NUMBER BETWEEN 1 AND 10
return (result !== 3) ? result : randOneToTenButNotThree(); // IF THE NUMBER IS NOT 3 RETURN THE RESULT, OTHERWISE CALL THIS FUNCTION AGAIN TO PICK ANOTHER NUMBER
}
var result = randOneToTenButNotThree(); // RESULT SHOULD BE A NUMBER BETWEEN 1 AND 10 BUT NOT 3
However, you could abstract this out to produce a random number in any given range, excluding any number of your choice:
var randExcl = function (lowest, highest, excluded) {
var result = Math.floor(Math.random() * (highest - lowest)) + lowest;
return (result !== excluded) ? result : randExcl();
}
var result = randExcl();
Just don't forget that if the function is renamed, you should also change the reference to it from within at the end of that return statement so that it can keep calling itself whenever it produces the excluded number.
This should work.
var r = 3;
while(r == 3) r = Math.ceil(Math.random() * 10);
function r(){a = Math.floor(Math.random() * 10) + 1; if (a==3) a++; return a;}