In traditional C++ programming, generating random numbers typically requires creating random number engines, distributors, and handling seed settings, resulting in verbose and complex code. effolkronium/random is an open-source random number library that addresses these issues with a concise and intuitive API, making random number generation in modern C++ simple and efficient.
Project Overview
effolkronium/random is a header-only random number library based on C++11, licensed under the MIT License. Its core advantage lies in providing an extremely simple API while maintaining high flexibility and performance.
Main features:
- Intuitive syntax – Generate various types of random numbers using the simple
get()method - Automatic seed management – The library automatically handles seed generation internally
- Thread-safe – Provides a thread-safe version
- Efficient performance – Uses
thread_localvariables to reduce memory overhead in multi-threaded environments - Header-only – Just include one header file to use it
Installation and Integration
Project Structure
effolkronium/random/
├── cmake/
│ ├── include/
│ │ └── effolkronium/
│ │ └── random.hpp
│ ├── test/
│ └── CMakeLists.txt
├── LICENSE
└── README.md
Integrating into Your Project
Simply include the main header file in your code:
#include "path/to/random.hpp"
// Or if installed in the system path
#include <effolkronium/random.hpp>
Basic Usage
Initialization and Namespace
// Use the main namespace
using Random = effolkronium::random;
// Or use the thread-safe version
using Random = effolkronium::random_thread_local;
Generating Random Numbers of Basic Types
#include <iostream>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
int main() {
// Generate an integer [0, 100]
auto randomInt = Random::get(0, 100);
std::cout << "Random Integer: " << randomInt << std::endl;
// Generate a floating-point number [0.0, 1.0]
auto randomDouble = Random::get(0.0, 1.0);
std::cout << "Random Floating Point: " << randomDouble << std::endl;
// Generate a boolean value
auto randomBool = Random::get<bool>();
std::cout << "Random Boolean: " << std::boolalpha << randomBool << std::endl;
// Generate a character
auto randomChar = Random::get('A', 'Z');
std::cout << "Random Character: " << randomChar << std::endl;
return 0;
}
Container-Related Operations
#include <vector>
#include <string>
#include <list>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
void containerExamples() {
std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
std::string text = "Hello, World!";
// Randomly select an element from the container
auto randomElement = Random::get(numbers);
auto randomChar = Random::get(text);
std::cout << "Randomly Selected Number: " << randomElement << std::endl;
std::cout << "Randomly Selected Character: " << randomChar << std::endl;
// Shuffle the container
Random::shuffle(numbers);
std::cout << "Shuffled Vector: ";
for (const auto& num : numbers) {
std::cout << num << " ";
}
std::cout << std::endl;
}
Advanced Features
Custom Distributions
#include <random>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
void distributionExamples() {
// Using normal distribution
auto normalDist = std::normal_distribution<double>(5.0, 2.0);
auto normalValue = Random::get(normalDist);
std::cout << "Normal Distribution Random Number: " << normalValue << std::endl;
// Using discrete distribution
std::vector<double> weights = {1.0, 2.0, 3.0, 2.0, 1.0};
auto discreteDist = std::discrete_distribution<int>(
weights.begin(), weights.end());
auto discreteValue = Random::get(discreteDist);
std::cout << "Discrete Distribution Random Number: " << discreteValue << std::endl;
}
Thread-Safe Usage
#include <thread>
#include <vector>
#include <effolkronium/random.hpp>
void threadSafeExample() {
constexpr int numThreads = 4;
std::vector<std::thread> threads;
for (int i = 0; i < numThreads; ++i) {
threads.emplace_back([](int threadId) {
// Each thread uses its own random number generator
using LocalRandom = effolkronium::random_thread_local;
for (int j = 0; j < 3; ++j) {
auto value = LocalRandom::get(1, 100);
std::cout << "Thread " << threadId
<< " Random Number: " << value << std::endl;
}
}, i);
}
for (auto& thread : threads) {
thread.join();
}
}
Practical Application Scenarios
Game Development
#include <vector>
#include <string>
#include <map>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
class GameRandomizer {
private:
std::vector<std::string> enemies_ = {"Goblin", "Orc", "Dragon", "Skeleton", "Wizard"};
std::vector<std::string> loot_ = {"Gold", "Potion", "Weapon", "Armor", "Gem"};
std::map<std::string, int> playerInventory_;
public:
// Randomly select an enemy
std::string getRandomEnemy() {
return Random::get(enemies_);
}
// Randomly generate loot
std::string getRandomLoot() {
return Random::get(loot_);
}
// Random enemy attributes
void generateRandomEnemyStats(int& health, int& attack, int& defense) {
health = Random::get(50, 200);
attack = Random::get(5, 30);
defense = Random::get(0, 20);
}
// Random event trigger (25% chance)
bool shouldTriggerRandomEvent() {
return Random::get(0.0, 1.0) < 0.25;
}
};
Test Case Generation
#include <vector>
#include <string>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
class TestDataGenerator {
public:
// Generate random strings
static std::string generateString(size_t length = 10) {
std::string result;
const std::string chars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for (size_t i = 0; i < length; ++i) {
result += Random::get(chars);
}
return result;
}
// Generate random integer arrays
static std::vector<int> generateIntArray(size_t size, int min = 0, int max = 100) {
std::vector<int> result;
result.reserve(size);
for (size_t i = 0; i < size; ++i) {
result.push_back(Random::get(min, max));
}
return result;
}
// Generate random email addresses
static std::string generateEmail() {
std::vector<std::string> domains = {
"gmail.com", "yahoo.com", "hotmail.com", "outlook.com"
};
return generateString(8) + "@" + Random::get(domains);
}
};
Scientific Computing and Simulation
#include <vector>
#include <cmath>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
class MonteCarloSimulation {
public:
// Monte Carlo π calculation
static double estimatePi(int numSamples) {
int pointsInsideCircle = 0;
for (int i = 0; i < numSamples; ++i) {
double x = Random::get(-1.0, 1.0);
double y = Random::get(-1.0, 1.0);
if (x * x + y * y <= 1.0) {
++pointsInsideCircle;
}
}
return 4.0 * pointsInsideCircle / numSamples;
}
// Random walk simulation
static std::vector<double> randomWalk(int steps, double stepSize = 1.0) {
std::vector<double> positions;
double position = 0.0;
for (int i = 0; i < steps; ++i) {
// Randomly choose direction: -1 or 1
int direction = Random::get(0, 1) ? 1 : -1;
position += direction * stepSize;
positions.push_back(position);
}
return positions;
}
};
Performance Optimization Techniques
Reduce Distribution Object Creation
// Efficient usage
void efficientRandomGeneration() {
// Reuse distribution objects
static auto intDist = std::uniform_int_distribution<int>(1, 100);
static auto realDist = std::uniform_real_distribution<double>(0.0, 1.0);
for (int i = 0; i < 1000; ++i) {
auto value1 = Random::get(intDist);
auto value2 = Random::get(realDist);
// Process random numbers...
}
}
Batch Random Number Generation
#include <array>
#include <effolkronium/random.hpp>
using Random = effolkronium::random_thread_local;
void batchGeneration() {
// Batch generate random numbers for performance improvement
constexpr size_t batchSize = 1000;
std::array<int, batchSize> randomNumbers;
for (size_t i = 0; i < batchSize; ++i) {
randomNumbers[i] = Random::get(1, 100);
}
// Or use standard algorithms to generate
std::generate(randomNumbers.begin(), randomNumbers.end(),
[]() { return Random::get(1, 100); });
}
Comparison with Traditional Methods
Traditional C++11 Approach
#include <random>
#include <chrono>
void traditionalApproach() {
// Requires creating multiple objects
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<int> dist(1, 100);
int randomValue = dist(gen);
}
Effolkronium/Random Approach
#include <effolkronium/random.hpp>
void modernApproach() {
using Random = effolkronium::random_thread_local;
// One line of code to achieve the same functionality
int randomValue = Random::get(1, 100);
}
Best Practices
-
Select the Right Random Number Generator:
- Use
effolkronium::randomin single-threaded environments - Use
effolkronium::random_thread_localin multi-threaded environments
-
Set Random Number Ranges Appropriately:
// Recommended: Explicitly specify the range auto value = Random::get(minValue, maxValue); -
Handle Random Number Seeds:
// When a fixed seed is needed (for testing) Random::getGenerator().seed(42); -
Combine with Standard Library Distributions:
// Make full use of various distributions in the standard library auto poisson = std::poisson_distribution<int>(4.0); auto value = Random::get(poisson);
Conclusion
Effolkronium/random greatly simplifies random number generation in C++ through its concise API, allowing developers to focus on business logic rather than the implementation details of random number generation. Its header-only feature makes integration very convenient, while the thread-safe version ensures reliability in multi-threaded environments.