Generating random whole numbers in JavaScript in a specific range

Viewed 1789117

How can I generate random whole numbers between two specified variables in JavaScript, e.g. x = 4 and y = 8 would output any of 4, 5, 6, 7, 8?

39 Answers

All these solutions are using way too much firepower. You only need to call one function: Math.random();

Math.random() * max | 0;

This returns a random integer between 0 (inclusive) and max (non-inclusive).

If you need a variable between 0 and max, you can use:

Math.floor(Math.random() *  max);

Cryptographically strong

To get a cryptographically strong random integer number in the range [x,y], try:

let cs = (x,y) => x + (y - x + 1)*crypto.getRandomValues(new Uint32Array(1))[0]/2**32 | 0

console.log(cs(4, 8))

Use this function to get random numbers in a given range:

function rnd(min, max) {
    return Math.floor(Math.random()*(max - min + 1) + min);
}

I wanted to explain using an example:

Function to generate random whole numbers in JavaScript within a range of 5 to 25

General Overview:

(i) First convert it to the range - starting from 0.

(ii) Then convert it to your desired range ( which then will be very easy to complete).

So basically, if you want to generate random whole numbers from 5 to 25 then:

First step: Converting it to range - starting from 0

Subtract "lower/minimum number" from both "max" and "min". i.e

(5-5) - (25-5)

So the range will be:

0-20 ...right?

Step two

Now if you want both numbers inclusive in range - i.e "both 0 and 20", the equation will be:

Mathematical equation: Math.floor((Math.random() * 21))

General equation: Math.floor((Math.random() * (max-min +1)))

Now if we add subtracted/minimum number (i.e., 5) to the range - then automatically we can get range from 0 to 20 => 5 to 25

Step three

Now add the difference you subtracted in equation (i.e., 5) and add "Math.floor" to the whole equation:

Mathematical equation: Math.floor((Math.random() * 21) + 5)

General equation: Math.floor((Math.random() * (max-min +1)) + min)

So finally the function will be:

function randomRange(min, max) {
   return Math.floor((Math.random() * (max - min + 1)) + min);
}

Here is a function that generates a random number between min and max, both inclusive.

const randomInt = (max, min) => Math.round(Math.random() * (max - min)) + min;

Math.random() is fast and suitable for many purposes, but it's not appropriate if you need cryptographically-secure values (it's not secure), or if you need integers from a completely uniform unbiased distribution (the multiplication approach used in others answers produces certain values slightly more often than others).

In such cases, we can use crypto.getRandomValues() to generate secure integers, and reject any generated values that we can't map uniformly into the target range. This will be slower, but it shouldn't be significant unless you're generating extremely large numbers of values.

To clarify the biased distribution concern, consider the case where we want to generate a value between 1 and 5, but we have a random number generator that produces values between 1 and 16 (a 4-bit value). We want to have the same number of generated values mapping to each output value, but 16 does not evenly divide by 5: it leaves a remainder of 1. So we need to reject 1 of the possible generated values, and only continue when we get one of the 15 lesser values that can be uniformly mapped into our target range. Our behaviour could look like this pseudocode:

Generate a 4-bit integer in the range 1-16.
If we generated  1,  6, or 11 then output 1.
If we generated  2,  7, or 12 then output 2.
If we generated  3,  8, or 13 then output 3.
If we generated  4,  9, or 14 then output 4.
If we generated  5, 10, or 15 then output 5.
If we generated 16 then reject it and try again.

The following code uses similar logic, but generates a 32-bit integer instead, because that's the largest common integer size that can be represented by JavaScript's standard number type. (This could be modified to use BigInts if you need a larger range.) Regardless of the chosen range, the fraction of generated values that are rejected will always be less than 0.5, so the expected number of rejections will always be less than 1.0 and usually close to 0.0; you don't need to worry about it looping forever.

const randomInteger = (min, max) => {
  const range = max - min;
  const maxGeneratedValue = 0xFFFFFFFF;
  const possibleResultValues = range + 1;
  const possibleGeneratedValues = maxGeneratedValue + 1;
  const remainder = possibleGeneratedValues % possibleResultValues;
  const maxUnbiased = maxGeneratedValue - remainder;

  if (!Number.isInteger(min) || !Number.isInteger(max) ||
       max > Number.MAX_SAFE_INTEGER || min < Number.MIN_SAFE_INTEGER) {
    throw new Error('Arguments must be safe integers.');
  } else if (range > maxGeneratedValue) {
    throw new Error(`Range of ${range} (from ${min} to ${max}) > ${maxGeneratedValue}.`);
  } else if (max < min) {
    throw new Error(`max (${max}) must be >= min (${min}).`);
  } else if (min === max) {
    return min;
  } 

  let generated;
  do {
    generated = crypto.getRandomValues(new Uint32Array(1))[0];
  } while (generated > maxUnbiased);

  return min + (generated % possibleResultValues);
};

console.log(randomInteger(-8, 8));          // -2
console.log(randomInteger(0, 0));           // 0
console.log(randomInteger(0, 0xFFFFFFFF));  // 944450079
console.log(randomInteger(-1, 0xFFFFFFFF));
// Error: Range of 4294967296 covering -1 to 4294967295 is > 4294967295.
console.log(new Array(12).fill().map(n => randomInteger(8, 12)));
// [11, 8, 8, 11, 10, 8, 8, 12, 12, 12, 9, 9]

IonuČ› G. Stan wrote a great answer, but it was a bit too complex for me to grasp. So, I found an even simpler explanation of the same concepts at Math.floor( Math.random () * (max - min + 1)) + min) Explanation by Jason Anello.

Note: The only important thing you should know before reading Jason's explanation is a definition of "truncate". He uses that term when describing Math.floor(). Oxford dictionary defines "truncate" as:

Shorten (something) by cutting off the top or end.

This I guess, is the most simplified of all the contributions.

maxNum = 8,
minNum = 4

console.log(Math.floor(Math.random() * (maxNum - minNum) + minNum))

console.log(Math.floor(Math.random() * (8 - 4) + 4))

This will log random numbers between 4 and 8 into the console, 4 and 8 inclusive.

A function called randUpTo that accepts a number and returns a random whole number between 0 and that number:

var randUpTo = function(num) {
    return Math.floor(Math.random() * (num - 1) + 0);
};

A function called randBetween that accepts two numbers representing a range and returns a random whole number between those two numbers:

var randBetween = function (min, max) {
    return Math.floor(Math.random() * (max - min - 1)) + min;
};

A function called randFromTill that accepts two numbers representing a range and returns a random number between min (inclusive) and max (exclusive)

var randFromTill = function (min, max) {
    return Math.random() * (max - min) + min;
};

A function called randFromTo that accepts two numbers representing a range and returns a random integer between min (inclusive) and max (inclusive):

var randFromTo = function (min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
};

You can you this code snippet,

let randomNumber = function(first, second) {
    let number = Math.floor(Math.random()*Math.floor(second));
    while(number < first) {

        number = Math.floor(Math.random()*Math.floor(second));
    }
    return number;
}

My method of generating a random number between 0 and n, where n <= 10 (n excluded):

Math.floor((Math.random() * 10) % n)

I made this function which takes into account options like min, max, exclude (a list of ints to exclude), and seed (in case you want a seeded random generator).

get_random_int = function(args={})
{
    let def_args =
    {
        min: 0,
        max: 1,
        exclude: false,
        seed: Math.random
    }

    args = Object.assign(def_args, args)

    let num = Math.floor(args.seed() * (args.max - args.min + 1) + args.min)

    if(args.exclude)
    {
        let diff = args.max - args.min
        let n = num

        for(let i=0; i<diff*2; i++)
        {
            if(args.exclude.includes(n))
            {
                if(n + 1 <= args.max)
                {
                    n += 1
                }

                else
                {
                    n = args.min
                }
            }

            else
            {
                num = n
                break
            }
        }
    }

    return num
}

It can be used like:

let n = get_random_int
(
    {
        min: 0,
        max: some_list.length - 1,
        exclude: [3, 6, 5],
        seed: my_seed_function
    }
)

Or more simply:

let n = get_random_int
(
    {
        min: 0,
        max: some_list.length - 1
    }
)

Then you can do:

let item = some_list[n]

Gist: https://gist.github.com/madprops/757deb000bdec25776d5036dae58ee6e

  • random(min, max) generates a random number between min (inclusive) and max (exclusive)

  • Math.floor rounds a number down to the nearest integer

      function generateRandomInteger(min, max) { 
          return Math.floor(random(min, max)) 
      }
    

So to generate a random integer between 4 and 8 inclusive, call the above function with the following arguments:

generateRandomInteger(4, 9)

For best performance, you can simply use:

var r = (Math.random() * (maximum - minimum + 1) ) << 0
// Example
function ourRandomRange(ourMin, ourMax) {
    return Math.floor(Math.random() * (ourMax - ourMin + 1)) + ourMin;
}

ourRandomRange(1, 9);

// Only change code below this line.
function randomRange(myMin, myMax) {
    var a = Math.floor(Math.random() * (myMax - myMin + 1)) + myMin;
    return a; // Change this line
}

// Change these values to test your function
var myRandom = randomRange(5, 15);

Using modern JavaScript + Lodash:

const generateRandomNumbers = (max, amount) => {
  const numbers = [...Array(max).keys()];
  const randomNumbers = sampleSize(numbers, amount);

  return randomNumbers.sort((a, b) => a - b);
};

Also, a TypeScript version:

const generateRandomNumbers = (max: number, amount: number) => {
  const numbers = [...Array(max).keys()];
  const randomNumbers: number[] = sampleSize(numbers, amount);

  return randomNumbers.sort((a: number, b: number) => a - b);
};

This implementation works when both inputs are integers.

function randomRange(myMin, myMax) {
  return Math.floor(
    Math.random() * (Math.ceil(myMax) - Math.floor(myMin) + 1) + myMin
  );
}

Problems with the accepted answer

It's worth noting that the accepted answer does not properly handle cases where min is greater than max. Here's an example of that:

min = Math.ceil(2);
max = Math.floor(1);
for(var i = 0; i < 25; i++) {
  console.log(Math.floor(Math.random() * (max - min + 1)) + min);
}

In addition, it's a bit wordy and unclear to read if you're unfamiliar with this little algorithm.

Why is Randojs a better solution?

Randojs handles cases where min is greater than max automatically (and it's cryptographically secure):

for(var i = 0; i < 25; i++) console.log(rando(2, 1));
<script src="https://randojs.com/1.0.0.js"></script>

It also handles negatives, zeros, and everything else you'd expect. If you need to do floats or use other variable types, there are options for that as well, but I won't talk about them here. They're on the site so you can delve deeper there if needed. The final reason is pretty obvious. Stylistically, it's is much cleaner and easier to read.


TL;DR. Just give me the solution...

randojs.com makes this and a ton of other common randomness stuff robust, reliable, as simple/readable as this:

console.log(rando(20, 30));
<script src="https://randojs.com/1.0.0.js"></script>

Here's something I found on a webpage:

function randomInt(e,t){return Math.floor(Math.random()*(t-e+1)+e)}
Related