A random integer in C++ is a value pulled from a range with no predictable pattern, and you produce one by combining a random-bit source (engine) with a distribution that maps those bits into your chosen minimum and maximum. The modern, recommended way is to include the <random> header, create a std::mt19937 engine seeded by std::random_device, and draw values through a std::uniform_int_distribution<int>(min, max); the older rand() approach still works but produces lower-quality sequences and biased endpoints. For tasks that don't need a compiled program — generating IDs for a spreadsheet, picking a sample for a survey, or choosing a winner from a numbered list — a browser-based tool is faster and just as fair.

how to generate random numbers in c++
how to generate random numbers in c++

Two Ways to Get a Random Number in C++

Most developers reach for one of two paths. The legacy path uses rand() from <cstdlib> with srand(time(0)) for a seed and the classic modulo trick to compress the output into a range. It compiles on every compiler and is easy to teach, but the results are not uniformly distributed across all integers and the maximum value is capped at RAND_MAX, which the C standard only requires to be at least 32767. The modern path uses the <random> header introduced in C++11, which separates the engine (the source of random bits) from the distribution (the shape of the output). This separation is the reason std::uniform_int_distribution gives you a truly uniform result across an inclusive range.

The Old Way: rand() and srand()

The classic pattern looks like this:

#include <iostream>
#include <cstdlib>
#include <ctime>

int main() {
    std::srand(static_cast<unsigned>(std::time(0)));
    int min = 1;
    int max = 100;
    int value = min + std::rand() % (max - min + 1);
    std::cout << value << std::endl;
    return 0;
}

It is short and readable, which is why tutorials still teach it. The catch is statistical: rand() returns values in [0, RAND_MAX], and when RAND_MAX + 1 is not a clean multiple of your range size, some output values appear slightly more often than others. For a game or a learning exercise this almost never matters. For simulation, cryptography, or any fairness-sensitive use, it does.

The Modern Way: std::mt19937 and uniform_int_distribution

If you want the textbook-correct pattern in C++, this is it:

#include <iostream>
#include <random>

int main() {
    std::random_device rd;
    std::mt19937 engine(rd());
    std::uniform_int_distribution<int> dist(1, 100);
    int value = dist(engine);
    std::cout << value << std::endl;
    return 0;
}

Three things are happening here. std::random_device reads nondeterministic bits from the operating system when available, so the seed is different on every run. std::mt19937 is a 32-bit Mersenne Twister engine that turns those seed bits into a long, high-quality pseudo-random sequence. std::uniform_int_distribution<int>(1, 100) guarantees that every integer from 1 to 100 inclusive is equally likely, including the two endpoints — which is the behavior most people actually want when they say "a random number between 1 and 100."

Generate Random Numbers in C++ Step by Step

  1. Include the right header. Add #include <random> at the top of your file. For the legacy path you would use #include <cstdlib> instead.
  2. Create a random-bit source. Instantiate std::random_device rd; for nondeterministic seeding, then wrap it in an engine such as std::mt19937 engine(rd());. If you only need determinism for testing, you can seed with a fixed integer instead.
  3. Define your range. Pick a minimum and maximum, both inclusive. For example, int min = 1; and int max = 100;.
  4. Create a distribution. Write std::uniform_int_distribution<int> dist(min, max);. Pass the engine to dist each time you want a value: int value = dist(engine);.
  5. Repeat if you need more than one. Call dist(engine) again. For a loop of 10 values from 1 to 50: for (int i = 0; i < 10; ++i) std::cout << dist2(engine) << " ";.
  6. Decide about duplicates. If repeats are not allowed, store each result in a std::set<int> or std::unordered_set<int> and keep drawing until you have enough unique values or bail out after a sensible retry limit.

When to Skip the Code and Use a Browser Tool Instead

Compiling a small C++ program just to pick a number from 1 to 50 is overkill. For classroom demos, giveaways, sampling, QA test data, or any task where you simply need a fair integer from a known range, an in-browser tool is faster. The Random Number Generator on Lizely runs entirely in your browser, lets you type a minimum and maximum safe integer, choose a result count from 1 to 1,000, and decide whether duplicates are allowed. Nothing leaves your machine, which makes it appropriate for sensitive samples and classroom environments alike.

Common Patterns and Edge Cases

A few patterns show up often enough to be worth memorizing. To generate a random double in [0, 1), use std::uniform_real_distribution<double> dist(0.0, 1.0);. To generate a random bool, use std::uniform_int_distribution<int> dist(0, 1); and convert. To pick one element from a std::vector, index it with dist(engine) % vec.size() only when vec.size() is small relative to the engine's range; for safety, wrap it in a std::uniform_int_distribution<std::size_t>(0, vec.size() - 1). Always re-create the distribution or reuse it carefully; the engine, not the distribution, holds the state that advances with each call.

Seed once, not in a loop

A frequent beginner mistake is calling srand(time(0)) (or even constructing std::mt19937(rd())) inside a loop that draws numbers. Because the clock resolution is one second, every draw in that loop sees the same seed and produces the same number. Seed exactly once, before the loop, and pass the engine in.

Inclusive endpoints vs. half-open ranges

std::uniform_int_distribution<int> is inclusive on both ends by design, which matches how most humans describe a range. The older rand() % n idiom is a half-open range [0, n) and silently throws away the maximum. If you migrate old code, double-check whether the original intent included the upper bound.

Comparing the Three Approaches

ApproachHeaderRange shapeQualityBest for
rand() + %<cstdlib>[min, max] via modulo trickLow; slight endpoint biasLearning exercises, throwaway scripts
std::mt19937 + uniform_int_distribution<random>Inclusive [min, max]High; uniformProduction code, simulations, games
Browser-based RNGNone (JS)Inclusive [min, max], 1–1,000 resultsHigh; runs locally via Web CryptoQuick picks, sampling, giveaways, classrooms

Putting It All Together

If you are writing C++, reach for std::mt19937 seeded by std::random_device and a std::uniform_int_distribution; that combination is short, portable, and statistically correct. If you need a single integer or a small batch for a non-programming task, skip the compile step entirely and use the Random Number Generator for inclusive integers that stay in your browser. For related workflows, the same pattern of "engine plus distribution" shows up when you generate a random number in MATLAB, and a broader overview of picking numbers without writing code lives in the how to generate random numbers for any task guide. If your numbers are really roll outcomes, the Dice Roller tool handles d4 through d20 with the same local-only philosophy.

FAQ-Style Notes Worth Remembering

Three quick reminders before you write any randomness code: std::uniform_int_distribution uses an inclusive upper bound, so dist(engine) can legally return your stated maximum; std::uniform_real_distribution uses a half-open upper bound and never returns exactly 1.0, which matters for division-by-uniform logic; and std::random_device can fall back to a deterministic engine on platforms without a hardware source, so do not rely on it alone for security-critical keys — for that, use a vetted cryptographic library rather than <random>.