SKU // 84

JavaScript Math Random

Dice rolls, shuffled quiz questions, random colors, loot drops, "pick a student": they all start with Math.random(). On its own it only gives a decimal between 0 and 1, so this lesson is mostly about turning that decimal into the kind of randomness you actually need.

// What Math.random() Gives You

Math.random()   // e.g. 0.7281947...
Math.random()   // e.g. 0.0412508...

Every call returns a new decimal that is at least 0 and less than 1. It can be exactly 0, but never exactly 1.

// Building a Random Whole Number, Step by Step

Math.random()                       // 0 to 0.999...
Math.random() * 6                   // 0 to 5.999...
Math.floor(Math.random() * 6)       // 0, 1, 2, 3, 4, or 5
Math.floor(Math.random() * 6) + 1   // 1, 2, 3, 4, 5, or 6  (a die!)
Use floor, Not round
Math.round(Math.random() * 6) gives 0 to 6, and 0 and 6 come up only half as often as the others, because only half a unit rounds to each end. Math.floor gives every number an equal chance.

// The Function You Will Reuse Forever

function randInt(min, max) {       // both ends included
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

randInt(1, 6)       // die roll
randInt(1, 100)     // 1 to 100
randInt(-10, 10)    // negatives work too
3 100 7 (varies every run)

The + 1 is what makes max reachable. Without it, randInt(1, 6) could never return 6.

// Is max Included?

There are two common versions of the random-integer function, and mixing them up is the classic off-by-one bug. The only difference is the + 1:

// min included, max EXCLUDED: good for array indexes
function randBelow(min, max) {
  return Math.floor(Math.random() * (max - min)) + min;
}

// min and max both INCLUDED: good for dice and 1-to-100 picks
function randInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

console.log(randBelow(0, 4));   // 0, 1, 2, or 3
console.log(randInt(0, 4));     // 0, 1, 2, 3, or 4
0 4 (varies every run)

Here is what each common expression can produce:

ExpressionSmallestLargest
Math.random()0just under 1
Math.random() * 100just under 10
Math.floor(Math.random() * 10)09
Math.floor(Math.random() * 11)010
Math.floor(Math.random() * 10) + 1110
Math.floor(Math.random() * 100) + 11100
Trap: 0 to 10 needs * 11
There are 11 whole numbers from 0 to 10, so you multiply by 11, not 10. The rule: multiply by how many different results you want, then add the smallest one.

Strictly speaking, JavaScript has no separate integer type: these are ordinary numbers that happen to have no decimals.

// Random Decimal in a Range

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

randFloat(98.0, 99.5).toFixed(1)   // e.g. "98.7"

// Picking a Random Item

const students = ["Ava", "Ben", "Cal", "Dee"];

const pick = arr => arr[Math.floor(Math.random() * arr.length)];

console.log(`Next up: ${pick(students)}`);
Next up: Ben (varies every run)

Multiplying by arr.length gives indexes 0 to length - 1, exactly the valid positions.

// Chances and Coin Flips

const heads = Math.random() < 0.5;           // 50% true
const critical = Math.random() < 0.1;        // 10% true

if (critical) console.log("Critical hit!");

// Weighted Choices

When options should not be equally likely, walk through them subtracting weights:

const loot = [
  { item: "coin",   weight: 70 },
  { item: "potion", weight: 25 },
  { item: "sword",  weight: 5 }
];

function weightedPick(options) {
  const total = options.reduce((sum, o) => sum + o.weight, 0);
  let roll = Math.random() * total;
  for (const o of options) {
    if (roll < o.weight) return o.item;
    roll -= o.weight;
  }
}

weightedPick(loot);   // "coin" about 70% of the time, "sword" about 5%
coin (usually; varies every run)

// Checking That It Is Fair

Randomness is hard to eyeball. Run it many times and count:

const counts = [0, 0, 0, 0, 0, 0];
for (let i = 0; i < 60000; i++) {
  counts[randInt(1, 6) - 1]++;
}
console.log(counts);
[9987, 10042, 9951, 10019, 9978, 10023] (about 10,000 each; varies every run)

// Not for Secrets

Security
Math.random() is fine for games and classroom tools, but its numbers can be predicted. Never use it for passwords, tokens, or anything security-related. Browsers provide crypto.getRandomValues() and crypto.randomUUID() for that.
crypto.randomUUID()   // e.g. "3b241101-e2bb-4255-8caf-4136c566a962"

For shuffling a whole array fairly, use the Fisher-Yates shuffle from the Array Sort lesson.

// Quick Check

Which gives a random whole number from 5 to 10, both included?

  1. Math.floor(Math.random() * 10) + 5
  2. Math.floor(Math.random() * 6) + 5
  3. Math.floor(Math.random() * 5) + 5
  4. Math.round(Math.random() * 5) + 5
Show answer
B. 5 to 10 is 6 possible results, so multiply by 6 and add 5. A goes up to 14, C never reaches 10, and D reaches 10 but makes 5 and 10 half as likely as the rest.

Can this ever log undefined?

const colors = ["red", "green", "blue"];
console.log(colors[Math.floor(Math.random() * colors.length) + 1]);
Show answer
Yes. The index ranges from 1 to 3, and colors[3] is undefined. It also never picks "red". Drop the + 1: array indexes start at 0.

Which is the right tool to generate a password-reset token?

  1. Math.random()
  2. Math.floor(Math.random() * 1e16)
  3. crypto.randomUUID()
  4. Date.now()
Show answer
C. Math.random() can be predicted, and so can a timestamp. Use the crypto methods for anything secret.

// Try It

  1. Click Open Playground. Finish rollDice(n) so it rolls n six-sided dice and returns the total
  2. Use pick to generate a random "adjective + animal" team name from two arrays
  3. Open the fairness test with its Try it Yourself button, change it to Math.round(Math.random() * 6), and see the uneven ends
  4. Make a random hex color: "#" + randInt(0, 0xFFFFFF).toString(16).padStart(6, "0")
// Video Walkthroughs
Last updated: Oct 10, 2026, 1:46 AM ET