Jump to content

Connect SuperML | Leeroopedia MCP: Equip your AI agents with best practices, code verification, and debugging knowledge. Powered by Leeroo — building Organizational Superintelligence. Contact us at founders@leeroo.com.

Implementation:ClickHouse ClickHouse PCG Random

From Leeroopedia


Knowledge Sources
Domains Random_Number_Generation
Last Updated 2026-02-08 00:00 GMT

Overview

PCG family of random number generators with multiple output functions, stream types, and state sizes.

Description

This header implements the complete PCG (Permuted Congruential Generator) family of random number generators. It provides multiple output functions (XSH RR, XSH RS, XSL RR, RXS M XS), four stream variants (single stream, MCG, settable stream, unique stream), support for arbitrary bit sizes, extended generators with large periods, and full C++11 random number engine interface compliance. The generators use LCG state advancement with carefully chosen multipliers and permutation functions to produce high-quality random output with excellent statistical properties.

Usage

Use PCG generators when you need high-quality, fast random numbers with good statistical properties, particularly when you need multiple independent streams, reproducible sequences, or very long periods for Monte Carlo simulations or statistical sampling.

Code Reference

Source Location

Signature

// Common typedefs
typedef pcg32;               // setseq_xsh_rr_64_32 - 64-bit state, 32-bit output
typedef pcg32_oneseq;        // oneseq_xsh_rr_64_32
typedef pcg32_unique;        // unique_xsh_rr_64_32
typedef pcg32_fast;          // mcg_xsh_rs_64_32

typedef pcg64;               // setseq_xsl_rr_128_64 - 128-bit state, 64-bit output
typedef pcg64_oneseq;        // oneseq_xsl_rr_128_64
typedef pcg64_fast;          // mcg_xsl_rr_128_64

// Core engine interface
template <typename xtype, typename itype, typename output_mixin,
          bool output_previous, typename stream_mixin, typename multiplier_mixin>
class engine {
public:
    typedef xtype result_type;
    typedef itype state_type;

    result_type operator()();                    // Generate next value
    result_type operator()(result_type bound);   // Bounded generation
    void seed(state_type state);                 // Reseed
    void advance(itype delta);                   // Jump ahead
    void backstep(itype delta);                  // Jump backward
    bool wrapped();                              // Check if cycled

    static constexpr result_type min();
    static constexpr result_type max();
    static constexpr size_t period_pow2();
};

// Extended generators with huge periods
typedef pcg32_k2;            // 2^65 period
typedef pcg32_k64;           // 2^2112 period (arc4random state size)
typedef pcg32_k1024;         // 2^32800 period (> Mersenne Twister)
typedef pcg32_k16384;        // 2^524352 period (party trick generator)

Import

#include "base/pcg-random/pcg_random.hpp"

I/O Contract

Generator Type State Size Output Size Period Stream Control
`pcg32` 64 bits 32 bits 2^64 Settable stream
`pcg32_oneseq` 64 bits 32 bits 2^64 Fixed stream
`pcg32_fast` 64 bits 32 bits 2^62 MCG (no stream)
`pcg64` 128 bits 64 bits 2^128 Settable stream
`pcg32_k2` 128 bits 32 bits 2^65 Extended table
`pcg32_k64` 512 bits 32 bits 2^2112 Extended table
`pcg32_k1024` 2176 bits 32 bits 2^32800 Extended table
`pcg64_k1024` 4224 bits 64 bits 2^131200 Extended table

Usage Examples

#include "base/pcg-random/pcg_random.hpp"
#include <iostream>

// Basic usage - default initialization
pcg32 rng;
uint32_t random_value = rng();

// Seed with specific value
pcg32 seeded_rng(42);  // Deterministic seed

// Seed with specific stream
pcg32 stream_rng(12345, 54321);  // State and stream

// Generate bounded random numbers (unbiased)
int die_roll = rng(6) + 1;       // [1, 6]
int card = rng(52);               // [0, 51]

// Multiple independent streams
pcg32 rng1(42, 1);  // Stream 1
pcg32 rng2(42, 2);  // Stream 2 (different sequence)

// Fast generator for speed-critical code
pcg32_fast fast_rng;
for (int i = 0; i < 1000000; ++i) {
    uint32_t value = fast_rng();
    // Process value...
}

// 64-bit output for larger values
pcg64 rng64;
uint64_t large_random = rng64();

// Jump ahead/backward in sequence
pcg32 main_rng(12345);
pcg32 future_rng = main_rng;
future_rng.advance(1000000);  // 1M steps ahead

// Check if generator wrapped around
while (!rng.wrapped()) {
    uint32_t value = rng();
    // Process until full cycle
}

// Extended generators for huge periods
pcg32_k64 huge_rng;  // 2^2112 period, same state as arc4random

// Use with standard library
std::uniform_real_distribution<double> dist(0.0, 1.0);
double random_double = dist(rng);

// Serialization
std::ostringstream state_out;
state_out << rng;
std::string saved_state = state_out.str();

std::istringstream state_in(saved_state);
pcg32 restored_rng;
state_in >> restored_rng;

// Monte Carlo simulation with parallel streams
void simulate_particle(int particle_id) {
    pcg32 rng(12345, particle_id);  // Each particle has unique stream
    for (int step = 0; step < 10000; ++step) {
        double x = std::uniform_real_distribution<>(-1, 1)(rng);
        double y = std::uniform_real_distribution<>(-1, 1)(rng);
        // Simulate particle motion...
    }
}

// Shuffle with PCG
template<typename T>
void shuffle_vector(std::vector<T>& vec, pcg32& rng) {
    for (size_t i = vec.size() - 1; i > 0; --i) {
        size_t j = rng(i + 1);
        std::swap(vec[i], vec[j]);
    }
}

// Random sampling
std::vector<int> random_sample(int population_size, int sample_size) {
    pcg32 rng(std::random_device{}());
    std::vector<int> sample;
    sample.reserve(sample_size);

    for (int i = 0; i < population_size && sample.size() < sample_size; ++i) {
        int remaining = population_size - i;
        int needed = sample_size - sample.size();
        if (rng(remaining) < needed) {
            sample.push_back(i);
        }
    }
    return sample;
}

// Performance comparison
#include <chrono>
void benchmark_generators() {
    const int N = 100000000;

    auto start = std::chrono::high_resolution_clock::now();
    pcg32 rng;
    uint64_t sum = 0;
    for (int i = 0; i < N; ++i) sum += rng();
    auto end = std::chrono::high_resolution_clock::now();

    std::cout << "PCG32: "
              << std::chrono::duration<double>(end - start).count()
              << " seconds\n";
}

Related Pages

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment