Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> C++

สร้างสุ่มตัวเลขใน C++: จาก rand() ไปสู่ (C++11)

การสร้างสุ่มตัวเลขใน C++ พัฒนาขึ้นมาอย่างมาก จาก C-style rand() ไปสู่ Modern C++ <random> Library (C++11) ที่ให้ Distribution, Engine และ Quality ที่ดีกว่ามาก

1. Legacy: rand() + srand() (C-style)

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

int main() {
    std::srand(std::time(nullptr)); // Seed ด้วยเวลา
    int max = 100;
    std::cout << "Random: " << (std::rand() % max) << '\n'; // 0-99
}

ข้อเสียร้ายแรง

  • Low Quality Randomness (LCG Algorithm)
  • Modulo Bias (% max ทำให้ Distribution เฉี้ยว)
  • Global State (Thread-Unsafe)
  • Range Hardcoded (RAND_MAX มัก 32767)

2. Modern C++: <random> Library (แนะนำ)

แยกเป็น 2 ส่วน: Engine (Generate Bits) และ Distribution (Map เป็น Range/Type)

Engine ที่แนะนำ

  • std::mt19937 (Mersenne Twister 32-bit) - Standard Choice
  • std::mt19937_64 (64-bit)
  • std::random_device - Non-deterministic (Hardware/OS Entropy) ใช้ Seed เท่านั้น

Distribution ที่พบบ่อย

Distributionใช้สำหรับRange
uniform_int_distribution<T>Integer แบบ Uniform[a, b] Inclusive
uniform_real_distribution<T>Float แบบ Uniform[a, b) หรือ [a, b]
normal_distribution<T>Normal (Gaussian)Mean, StdDev
bernoulli_distributionBoolean (Coin Flip)Probability p
poisson_distribution<T>PoissonMean

ตัวอย่างสมบูรณ์ (Best Practice)

#include <random>
#include <iostream>
#include <vector>

int main() {
    // 1. Seed Engine ด้วย random_device (Non-deterministic)
    std::random_device rd;
    std::mt19937 gen(rd()); // Engine

    // 2. Define Distributions
    std::uniform_int_distribution<> dice(1, 6);           // ทอยเต๋า 1-6
    std::uniform_real_distribution<> prob(0.0, 1.0);       // Float 0-1
    std::normal_distribution<> dist(5.0, 2.0);             // Normal μ=5, σ=2

    // 3. Generate
    std::cout << "Dice rolls: ";
    for (int i = 0; i < 10; ++i) std::cout << dice(gen) << ' ';
    std::cout << '\n';

    std::cout << "Random floats: ";
    for (int i = 0; i < 5; ++i) std::cout << prob(gen) << ' ';
    std::cout << '\n';

    // 4. Reproducible Seed (สำหรับ Testing/Debug)
    std::mt19937 gen_fixed(42); // Fixed Seed
    std::cout << "Fixed seed: " << dice(gen_fixed) << '\n';

    return 0;
}

Thread Safety

แต่ละ Thread ควรมี Engine ตัวเอง (Thread-Local Storage):

thread_local std::mt19937 thread_gen(std::random_device{}());

int random_int(int min, int max) {
    std::uniform_int_distribution<> dist(min, max);
    return dist(thread_gen);
}

Performance Tips

  • Reuse Engine และ Distribution Object (อย่าสร้างใหม่ใน Loop)
  • ใช้ std::uniform_int_distribution แทน % เพื่อหลีกเลี่ยง Modulo Bias
  • สำหรับ Cryptography: ใช้ std::random_device โดยตรง หรือ Crypto Library (OpenSSL, libsodium)

สรุป

ห้ามใช้ rand() ในโค้ด Modern C++ ใช้ <random> แทน: std::mt19937 + std::uniform_int_distribution ให้ Quality, Flexibility, Thread-Safety และ Standard Compliance ที่ดีที่สุด