如何生成符合自定义周期与振幅的压缩余弦分布随机数
生成指定周期和振幅的余弦分布随机数(Ruby实现)
问题分析
你需要生成0-1区间内的随机数,其概率分布符合指定周期数的余弦曲线,且峰值概率是低谷的factor倍。之前的代码错误地使用了线性缩放均匀随机数的方式,无法正确匹配目标分布,导致结果不符合预期。
核心思路:逆变换采样
要生成符合自定义概率密度函数(PDF)的随机数,正确的方法是逆变换采样:
- 构造目标PDF:在0-1区间内有
intervals个峰值,峰值/低谷概率比为factor - 计算累积分布函数(CDF)
- 通过数值方法求解CDF的逆函数,将均匀随机数转换为目标分布的随机数
正确实现代码
def randcos(factor:, intervals:) return rand if factor == 1 # 因子为1时退化为均匀分布 # 预计算常数 c = (factor - 1.0) / ((factor + 1.0) * 2 * intervals * Math::PI) two_pi_intervals = 2 * intervals * Math::PI # 生成均匀随机数u∈[0,1] u = rand # 牛顿迭代法求解CDF(y) = u # 初始猜测值设为u(接近均匀分布的解) y = u 10.times do # 迭代10次足够收敛 # CDF(y) = y + c*sin(two_pi_intervals*y) cdf = y + c * Math.sin(two_pi_intervals * y) # CDF的导数(即PDF)= 1 + c*two_pi_intervals*cos(two_pi_intervals*y) pdf = 1 + c * two_pi_intervals * Math.cos(two_pi_intervals * y) # 牛顿迭代更新:y = y - (CDF(y)-u)/PDF(y) y -= (cdf - u) / pdf # 确保y在0-1范围内 y = [[y, 0.0].max, 1.0].min end y end
代码解释
- 常数预计算:根据目标分布的参数(
factor和intervals)计算CDF中的常数项,避免重复计算 - 均匀随机数生成:生成基础的均匀分布随机数
u - 牛顿迭代求解:通过迭代求解CDF的逆函数,得到符合目标分布的随机数
y,迭代10次足以保证精度 - 边界处理:确保最终结果落在0-1区间内
测试验证
用你提供的示例代码测试:
# 生成10000个样本并分组 samples = 10_000.times.map do num = randcos(factor: 5, intervals: 3) (num * 13).floor # 分为12组 end # 统计每组频率 frequency = samples.tally.sort.to_h puts frequency
运行后,你会看到分组后的频率呈现3个明显的峰值,低谷频率约为峰值的1/5,符合预期。
为什么之前的代码失败?
你之前的代码错误地将均匀采样的x代入余弦函数后,再用另一个均匀随机数相乘,这种方式无法正确模拟目标概率分布。逆变换采样是生成自定义分布随机数的标准方法,能严格匹配你需要的余弦曲线分布。
内容的提问来源于stack exchange,提问作者Rockster160
相关产品推荐
相关产品推荐

