View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All
View All

Random Number Generator in C++

Updated on 03/02/2025464 Views

Random numbers are a core component behind a lot of applications, injecting unpredictability and variety into software. They are indispensable for simulations, gaming, cryptography, statistical sampling, and numerous algorithms. Random number generators are essential in programming in general, similarly being extremely useful in C++ programs as well.

In this tutorial, I will discuss the different types of random number engines available in C++ and how to generate numbers that are random in cpp. We will then explore the concept of seeding and its crucial role in ensuring the quality and variability of our random number sequences. Finally, we'll also examine various probability distributions and demonstrate how to use them to generate random numbers tailored to our specific applications.

Let us dive in and learn about working with a random number generator in C++.

Random Numbers in C++

Simulations rely on randomness to model real-world scenarios with accurate variations, while games utilize random number generation to create engaging and unpredictable experiences. In cryptography, randomness ensures robust security, while statistical sampling depends on it for fair and representative data collection.

However, it is important to understand the distinction between true randomness and pseudorandomness. True randomness stems from unpredictable physical phenomena, such as atmospheric noise or quantum effects, and is inherently non-deterministic. In contrast, pseudorandomness relies on algorithms to generate sequences of numbers that appear random but are, in fact, deterministic and repeatable given the same starting conditions.

C++, while capable of utilizing true random data sources, primarily focuses on providing powerful and efficient mechanisms for generating pseudorandom numbers. The Standard Library allows us to work with numbers that are random in C++, specifically the <random> header introduced in C++11, equips developers with a comprehensive toolkit for generating high-quality pseudorandom numbers with excellent statistical properties. This toolkit includes various random number engines, which serve as the core generators of random values, and distributions, which shape the output of these engines to fit specific needs.

The <random> Header: C++'s RNG Toolbox

The <random> header, introduced in C++11, revolutionized random number generation in C++, offering a flexible and powerful framework for creating high-quality pseudorandom values. This header provides two main building blocks: random number engines and distributions.

Random Number Engines

Random number engines are the core generators of pseudorandom values in C++. They act as the source of randomness, producing sequences of numbers that appear unpredictable. Think of them as the "powerhouse" that fuels the random number generation process. The <random> header offers several engine options:

  1. std::default_random_engine: This is the default engine for generating values that are random in cpp, but its specific implementation may vary depending on the compiler and standard library. It provides a decent level of randomness for many general-purpose applications.
  1. std::linear_congruential_engine: This engine uses a simple linear equation to generate the next number in the sequence. It's fast but might not be suitable for applications demanding high-quality randomness.
  1. std::mersenne_twister_engine: Widely considered the gold standard for most applications, the Mersenne Twister algorithm generates high-quality pseudorandom numbers with a very long period before the sequence repeats. It is a good default choice when we need reliable randomness.

Distributions: Shaping the Random Output

While engines generate random numbers, they often produce values within a specific range (e.g., between 0 and a large maximum value). Distributions come into play to transform this raw output into numbers that follow specific probability distributions, making them suitable for different tasks.

Here are some commonly used distributions:

  • std::uniform_int_distribution: Generates integers within a specified range with equal probability for each value. (Think of rolling a fair die.)
  • std::uniform_real_distribution: Produces floating-point numbers within a given range with uniform probability.
  • std::normal_distribution: Generates numbers according to a normal (Gaussian) distribution, creating a bell-shaped curve where values closer to the mean are more likely.
  • std::bernoulli_distribution: Simulates a coin flip, returning either true or false with a given probability.

The Power of Combining Engines and Distributions

The true strength of the <random> header lies in its flexibility. By combining different engines with various distributions, we can create a wide array of tailored random number generators, perfectly suited to our specific needs. This modular approach allows us to select the best engine for performance and the ideal distribution for the statistical properties we require.

Generating Random Numbers: A Practical Guide

Now that we have explored the building blocks of cpp random number generation, let us put them together to generate random values that meet our specific requirements. Follow these five steps:

1. Include <random>

The first step is to ensure that our C++ code has access to the powerful tools in the <random> header. Include it at the beginning of your file:

#include <random>

2. Choose an Engine

Select a random number engine that balances your needs for speed and randomness quality. Here are common choices:

  • std::mt19937: A robust and widely-used engine known for its good statistical properties.
  • std::default_random_engine: A compiler-specific engine, often suitable for general-purpose use.
  • std::linear_congruential_engine: A faster but potentially less random engine.

Create an instance of your chosen engine:

std::mt19937 rng; // Mersenne Twister engine

3. Seed the Engine

Seeding is the process of initializing the engine with a starting value. This ensures that the sequence of random numbers we generate is different each time we run our program.

A good practice is to use std::random_device for obtaining a truly random seed:

std::random_device rd;
std::mt19937 rng(rd());

If std::random_device is not available, we can use the current time as a seed (though less ideal):

std::mt19937 rng(std::time(0));

4. Choose a Distribution

Determine the range and type of random values you need. Select the appropriate distribution:

  • std::uniform_int_distribution: For evenly distributed integers within a range.
  • std::uniform_real_distribution: For evenly distributed floating-point numbers within a range.
  • std::normal_distribution: For normally distributed (bell curve) values.
  • std::bernoulli_distribution: For simulating events with two possible outcomes (e.g., coin flips).

Create a distribution object, specifying its parameters (if needed):

std::uniform_int_distribution<int> dist(1, 6); // 1 to 6 (inclusive)
  1. Generate Random Numbers

Finally, use the engine and distribution together to generate random values:

int randomValue = dist(rng); // Generate a random value using the engine

Repeat this as needed within a loop or call it on-demand to generate individual random numbers. Finally, we should always remember that thoughtful seeding and appropriate distribution selection are crucial for obtaining high-quality random numbers that suit our specific needs.

Random Number Generator in C++ Examples

1. Simulating Dice Rolls

Code:

#include <iostream>

#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dist(1, 6); // Distribution for values 1 to 6
std::cout << "Rolling a die 10 times: ";
for (int i = 0; i < 10; ++i) {
std::cout << dist(gen) << " ";
}
std::cout << std::endl;
}

We use a random device to seed a Mersenne Twister engine (std::mt19937). Then, we create a uniform integer distribution (std::uniform_int_distribution) to generate random values from 1 to 6 (inclusive), simulating the roll of a standard die.

If you wish to learn how to code in C++, you can check out upGrad’s software engineering courses.

2. Random Point Generation

Code:

#include <iostream>
#include <random>
int main() {
std::random_device rd;
std::mt19937 gen(rd());

// 2D point (x, y) between 0.0 and 100.0
std::uniform_real_distribution<> distX(0.0, 100.0);
std::uniform_real_distribution<> distY(0.0, 100.0);
for (int i = 0; i < 5; ++i) {
double x = distX(gen);
double y = distY(gen);
std::cout << "Point " << i + 1 << ": (" << x << ", " << y << ")\n";
}
}

Similar to the dice roll example, we seed an engine and then create two separate uniform real distributions (std::uniform_real_distribution) to generate random x and y coordinates between 0.0 and 100.0, producing five random points in a 2D space.

3. Shuffling a Deck of Cards

Code:

#include <iostream>
#include <random>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::string> deck = {"Ace", "2", "3", /* ... , */ "King"};
std::random_device rd;
std::mt19937 gen(rd());
std::shuffle(deck.begin(), deck.end(), gen); // Shuffle the deck
std::cout << "Shuffled deck:\n";
for (const std::string& card : deck) {
std::cout << card << " ";
}
std::cout << std::endl;
}

We create a vector representing a deck of cards. We use the std::shuffle algorithm from the <algorithm> header, which takes our random number engine (gen) as a parameter to randomly reorder the elements in the deck.

Best Practices for Random Number Generation

Generating random numbers may seem simple, but there are nuances that can significantly impact the quality and predictability of our results. Adhering to best practices ensures our random numbers are as random as we need them to be.

1. Seed Carefully

Seeding our random number engine is like giving it a starting point for its calculations. A good seed ensures that the generated sequence appears unpredictable and varies between different program runs. Here is what we need to know:

  • std::random_device (preferred): This device extracts non-deterministic random numbers from our computer's hardware (if available). It's the most reliable way to seed our engine and produces high-quality random numbers.
std::random_device rd;
std::mt19937 gen(rd());
  • System time (fallback): If std::random_device is unavailable, using the current time as a seed is a common workaround. However, this method is less secure and might produce similar sequences if our program is run repeatedly within short intervals.
std::mt19937 gen(std::time(0));
  • Never seed with a fixed value: Using a constant seed (e.g., std::mt19937 gen(42);) will always produce the same sequence of numbers, defeating the purpose of randomness.

2. Use the Right Distribution

Choosing the right probability distribution is crucial for achieving the desired behavior in our random numbers. Consider the following:

  • std::uniform_int_distribution: When we need random integers within a specific range where each value has an equal chance of being selected.
  • std::uniform_real_distribution: Similar to uniform_int_distribution, but for floating-point numbers.
  • std::normal_distribution: When we need a bell-shaped (Gaussian) distribution, where values closer to the mean are more frequent.
  • std::bernoulli_distribution: For simulating binary events with a certain probability of success (like a coin toss).

You can explore the <random> header for a wide range of other distributions. To experiment more, you can try to work on a custom random number generator in C++ within a range.

3. Avoid Common Pitfalls

  1. The rand() function: Avoid the old C-style rand() function. This C++ rand function often produces lower-quality random numbers and lacks the flexibility of the C++11 random number library.
  1. Incorrect seeding: Don't re-seed your engine too frequently. A single good seed at the start of our program is usually sufficient.
  1. Ignoring error conditions: Always check if random device operations are successful before using them for seeding.

Final Tips

Selecting the appropriate cpp random number engine and distribution is crucial. We should always consider factors like performance, statistical quality, and the desired range and type of our random numbers.

I also find it extremely important to mention that we must always seed our random number engine to ensure unpredictable sequences. We can favor std::random_device for truly random seeds, or use system time as a fallback if necessary. Finally, we should steer clear of the outdated rand() function, and avoid incorrect seeding or frequent re-seeding practices.

By following these guidelines and adhering to the best practices I discussed, we can guarantee that our random number generation is both reliable and high-quality in C++ programming. Gaining expertise in working with random number generator in C++ will also set the stage for robust simulations, engaging games, and secure cryptographic applications.

Embrace the power of randomness, and let your C++ code flourish with unpredictability. If you wish to learn programming languages such as C++, you can check out upGrad’s computer science programs such as the Master’s in Computer Science Program.

Frequently Asked Questions

  1. What is a random number generator (RNG) in C++?

In C++, a random number generator (RNG) is a mechanism (usually an algorithm) for producing a sequence of numbers that lack any discernible pattern.

  1. How do I generate random numbers in C++?

You combine a random number engine (like std::mt19937) with a distribution (like std::uniform_int_distribution) from the <random> header.

  1. Which random number generation engine should I use?

For most applications, the std::mt19937 engine provides a good balance of speed and statistical quality.

  1. What is the rand () function in C++?

The rand() function is an older, C-style way to generate random numbers, but it's less flexible and has potential quality issues compared to modern C++ methods.

  1. How to generate a random number in C++ without a random function?

True randomness requires external sources like hardware noise or atmospheric data, but you can approximate it with techniques like linear congruential generators (though less reliable than modern RNGs).

  1. How do I generate random numbers in C++11 and later versions?

Use the classes and functions in the <random> header, which provides a much more robust and flexible framework for random number generation.

  1. Is the C++ random number generator truly random?

No, the random numbers generated by C++ algorithms are pseudorandom – they follow a deterministic pattern but appear random for practical purposes.

  1. Are random numbers generated by C++ secure for cryptography?

No, the standard C++ random number generators are not cryptographically secure. You need specialized libraries for generating cryptographically secure random numbers.

image
Join 10M+ Learners & Transform Your Career
Learn on a personalised AI-powered platform that offers best-in-class content, live sessions & mentorship from leading industry experts.
advertise-arrow

Free Courses

Start Learning For Free

Explore Our Free Software Tutorials and Elevate your Career.

upGrad Learner Support

Talk to our experts. We are available 7 days a week, 9 AM to 12 AM (midnight)

text

Indian Nationals

1800 210 2020

text

Foreign Nationals

+918045604032

Disclaimer

1.The above statistics depend on various factors and individual results may vary. Past performance is no guarantee of future results.

2.The student assumes full responsibility for all expenses associated with visas, travel, & related costs. upGrad does not provide any a.