当前位置: 首页 > news >正文

C++ 的随机整数采样

文章目录

  • 1. 采样示例
  • 2. 源码 random_number_sampler.cpp
  • 3. 使用方式


1. 采样示例

无放回 without replacement 的随机整数采样,和有放回的随机整数采样,是两个常见的功能。 C++ 没有直接提供这个功能,std::sample 只用于无放回的采样,因此可以手动创建,让使用起来更方便。使用的效果如下。

  1. 无放回的采样示例。
    从 [2025, 888, 666] 三个数中进行采样,得到一个随机数。当采样次数超过总体的数量之后,进行报错。运行结果如下图。
    代码中实际的做法,是先将 3 个数打乱,再从后向前,一个一个地取出数据。
    请添加图片描述

  2. 有放回的采样示例。
    从范围 [6, 8] 直接进行采样。因为是有放回的方式,所以可以无限次采样。代码运行结果如下。 请添加图片描述


2. 源码 random_number_sampler.cpp

#include <algorithm>
#include <cstdlib>
#include <format>
#include <initializer_list>
#include <iostream>
#include <mutex>
#include <random>
#include <stdexcept>
#include <string>
#include <vector>/*
一个随机采样的 class,包括有放回 with replacement 和无放回两种。
输入:一个范围,如 [6, 8] 。输出:采样出一个数值。
有放回采样允许无限次采样。
无放回采样在将所有数值采样结束后,再次采样将抛出异常。
*/
class RandomIntegerSampler {public:// 手动指定几个数值采样时,使用大括号初始化对象。explicit RandomIntegerSampler(std::initializer_list<int> arguments) : uniform_dist_(0, arguments.size() - 1){if (arguments.size() == 0) {throw std::range_error("Argument size must bigger than 0");}for (const auto& each : arguments) {population_.emplace_back(each);}shuffle_population();}// 在 [low, high] 范围内采样时,用小括号初始化对象。RandomIntegerSampler(int low, int high) : population_(high - low + 1), uniform_dist_(0, high - low){// 初始化 population_ 时,把 high 也包括进去,所以要加 1 。if (low > high) {std::string info{"Argument low must no bigger than high, bug got low= " + std::to_string(low) + "\t high= " + std::to_string(high)};throw std::range_error(info);}std::iota(population_.begin(), population_.end(), low);shuffle_population();}void show_population() {std::cout << "elements in container:  ";std::string format_str = "{: >6}";  // 右对齐,每个输出占 6 个空格位置。for (const auto& each : population_) {std::cout << std::vformat(format_str, std::make_format_args(each));}std::cout << "\n";}// 该函数用于无放回 without replacement 的采样。int no_replacement() {std::scoped_lock lock{mtx_};  // 多线程时用 mutex 进行保护。if (population_.empty()) {throw std::length_error{"Empty population, no sampling allowed!"};}int a{population_.back()};population_.pop_back();  // 必须清除掉已采样数值。return a;}// 该函数用于有放回 with replacement 的采样。int with_replacement() {std::scoped_lock lock{mtx_};  // 多线程时用 mutex 进行保护。int index{uniform_dist_(unsigned_int_generator_)};return population_[index];}private:std::vector<int> population_{};  // 采样的总体。std::mutex mtx_;// 用于后续的有放回采样。std::mt19937_64 unsigned_int_generator_{};  // 准备均匀分布的随机无符号整数。std::uniform_int_distribution<> uniform_dist_{};void shuffle_population() {std::random_device rd_seed;  // 准备随机种子。unsigned_int_generator_.seed(rd_seed());  // 第一次 seed ,用于 shuffle 。// 打乱数据,生成随机序列。std::shuffle(population_.begin(), population_.end(), unsigned_int_generator_);// 第二次 seed ,用于后续的采样,解决一个问题:如果 shuffle 时 vector 中的数量极大,后续采样随机性会降低。unsigned_int_generator_.seed(rd_seed());  }
};
void demo_no_replacement() {std::cout << "无放回的随机采样,3 个数值 [2025, 888, 666]\n";RandomIntegerSampler sampler{2025, 888, 666};sampler.show_population();for (int i = 0; i < 5; ++i) {std::cout << "sampled[" << i << "]= " << sampler.no_replacement() << "\n";}
}
void demo_no_replacement_range() {std::cout << "无放回的随机采样,数值范围 [6, 8]\n";RandomIntegerSampler sampler(9, 8);sampler.show_population();for (int i = 0; i < 5; ++i) {std::cout << "sampled[" << i << "]= " << sampler.no_replacement() << "\n";}
}
void demo_with_replacement_range() {std::cout << "有放回的随机采样,数值范围 [6, 8]\n";RandomIntegerSampler sampler(6, 8);sampler.show_population();for (int i = 0; i < 5; ++i) {std::cout << "sampled[" << i << "]= " << sampler.with_replacement() << "\n";}
}int main() {demo_no_replacement();// demo_no_replacement_range();// demo_with_replacement_range();return 0;
}

3. 使用方式

创建了上面的 RandomIntegerSampler 之后,采样就会更方便,使用方式如下:

RandomIntegerSampler sampler{2025, 888, 666};sampler.no_replacement();  // 无放回的采样,得到一个整数。sampler.with_replacement();  // 有放回的采样,得到一个整数。

—————————— 本文结束 ——————————

http://www.dtcms.com/a/361277.html

相关文章:

  • 【106】基于51单片机智能油烟机/换气扇【Proteus仿真+Keil程序+报告+原理图】
  • 计算机视觉(五):blur
  • 解锁水系电池机理:原位谱学测试方案全解析-测试GO
  • Apache Commons ConvertUtils
  • FFMPEG 10BIT下 Intel b570 qsv 硬解AV1,H265视频编码测试
  • 《Shell 大道:筑基篇(上)—— 神念控流程,函数成符阵》
  • 机器学习——模型架构
  • ✝常用表格✝
  • 读《独角兽项目:数字化转型》
  • 【开题答辩全过程】以 基于微信小程序的校园二手物品交易平台的设计与实现为例,包含答辩的问题和答案
  • 分布式光伏模式怎么选?从 “凭经验” 到 “靠数据”,iSolarBP 帮你锁定最优解
  • 苹果WWDC25开发秘鉴:AI、空间计算与Swift 6的融合之道
  • 领码方案:低代码平台前端缓存与 IndexedDB 智能组件深度实战
  • GDAL 简介
  • FAST API部署和使用
  • java讲解自己对业务架构、数据架构、应用架构的理解
  • gh-pages部署github page项目
  • 【机器学习入门】5.1 线性回归基本形式——从“选西瓜”看懂线性模型的核心逻辑
  • A2A + MCP 的python实现的最小可运行骨架
  • duilib中CTextUI控件使用技巧与问题总结(CTextUI控件自适应文字宽度特性)
  • 五、练习2:Git分支操作
  • 四、操作系统
  • 腾讯混元翻译大模型Hunyuan-MT-7B:重塑跨语言沟通的技术革命
  • 2025年应届生求职加分指南:这些新兴技能路径让你脱颖而出
  • 电子电气架构 --- 智能电动车EEA电子电气架构(下)
  • 【LeetCode 热题 100】5. 最长回文子串——中心扩散法
  • Linux按键输入实验
  • (纯新手教学)计算机视觉(opencv)实战十一——轮廓近似(cv2.approxPolyDP)
  • Python OpenCV图像处理与深度学习:Python OpenCV特征检测入门
  • “人工智能+”时代的端侧AI:算力下沉与实时视频的新基座