C++ C++;随机数生成:生成cos平方函数
兴趣的概率分布是C++ C++;随机数生成:生成cos平方函数,c++,c++11,random,probability,probability-density,C++,C++11,Random,Probability,Probability Density,兴趣的概率分布是 double x; // range: -pi/2.0 to +pi/2.0 double y = std::pow(std::cos(x), 2.0); 该函数可以通过分析进行积分,但不能倒置。因此,无法执行将均匀分布映射到所需概率分布的常规技巧 有没有其他方法可以用来生成随机变量cos^2(θ)分布 也许可以用数值方法找到反函数,但是我不知道有什么有效的(内存和计算)方法可以做到这一点。来源:你可以根据任何概率分布随机生成样本数,给定其cdf 假设您想要cos2x分布,从
double x; // range: -pi/2.0 to +pi/2.0
double y = std::pow(std::cos(x), 2.0);
该函数可以通过分析进行积分,但不能倒置。因此,无法执行将均匀分布映射到所需概率分布的常规技巧
有没有其他方法可以用来生成随机变量cos^2(θ)分布
也许可以用数值方法找到反函数,但是我不知道有什么有效的(内存和计算)方法可以做到这一点。来源:你可以根据任何概率分布随机生成样本数,给定其cdf
假设您想要cos2x分布,从-pi/2到pi/2。因为cos2x从-pi/2到pi/2的积分是pi/2,所以需要缩小比例,使积分为1。因此,pdf P(x)=(2/pi)cos2x
下一步是从给定的pdf计算cdf,这是pdf的积分。你可以用任何数值方法来求P(x)的积分。或者你可以去Wolfram Alpha得到答案:cdf是F(x)=(2/pi)(0.5x+0.25sin2x)+0.5
接下来需要计算F-1(x)。因为F(x)是一个单调递增函数,所以可以使用二分法(二进制搜索)轻松地找到F-1(x)。Wolfram Alpha没有这个F-1(x)公式
然后生成一个从0到1的统一实数u。您的自定义发行版是F-1(u)
From:您可以根据任意概率分布随机生成样本数,给定其cdf
假设您想要cos2x分布,从-pi/2到pi/2。因为cos2x从-pi/2到pi/2的积分是pi/2,所以需要缩小比例,使积分为1。因此,pdf P(x)=(2/pi)cos2x
下一步是从给定的pdf计算cdf,这是pdf的积分。你可以用任何数值方法来求P(x)的积分。或者你可以去Wolfram Alpha得到答案:cdf是F(x)=(2/pi)(0.5x+0.25sin2x)+0.5
接下来需要计算F-1(x)。因为F(x)是一个单调递增函数,所以可以使用二分法(二进制搜索)轻松地找到F-1(x)。Wolfram Alpha没有这个F-1(x)公式
然后生成一个从0到1的统一实数u。您的自定义发行版是F-1(u)
拒绝采样是否可接受?这不能是分布-其在范围内的积分不等于1。如果按
2/pi
缩放它,它可能会被回收。为了避免麻烦,这种情况下的累积分布函数是F(x)=(x+sin(2*x)/2+pi/2)/pi
@IgorTandetnik良好点-我没有对其进行规范化,因为规范化取决于x的范围-因为我写了这篇文章,我认为使用0到pi/2.0的范围可能更容易,而不是问题中指定的原始范围。拒绝采样是否可接受?这不能是分布-其在该范围内的积分不等于1。如果按2/pi
缩放它,它可能会被回收。为了避免麻烦,这种情况下的累积分布函数是F(x)=(x+sin(2*x)/2+pi/2)/pi
@IgorTandetnik良好点-我没有对其进行规范化,因为规范化取决于x的范围-因为我写了这篇文章,我认为使用0到pi/2.0的范围可能更容易,而不是问题中规定的原始范围。
#include <iostream>
#include <cmath>
#include <random>
#include <boost/random/random_device.hpp>
#include <vector>
#include <iomanip>
const double pi = 3.14159265358979323846;
const double LOW = -pi/2;
const double HIGH = pi/2;
double pdf(double x)
{
return cos(x) * cos(x);
}
double cdf(double x) //integral of pdf
{
return (2/pi)*(x/2 + sin(2*x)/4) + 0.5; //from Wolfram Alpha
}
double inverse_cdf(double u)
{ //bisection, not 100% accurate
double low = LOW;
double high = HIGH;
double epsilon = 1e-10; //any small number, e.g. 1e-15
while (high - low > epsilon)
{
double mid = (low + high) / 2;
if (cdf(mid) == u) return mid;
if (cdf(mid) < u) low = mid; else high = mid;
}
return (low + high) / 2;
}
double custom_distribution(std::mt19937& rng)
{
double u = std::uniform_real_distribution<double>(0,1)(rng);
return inverse_cdf(u);
}
int main()
{
std::mt19937 rng{boost::random::random_device{}()};
std::vector<double> xCount(15);
int nSamples = 10000;
double gap = (HIGH-LOW) / xCount.size();
while (nSamples--) xCount[(int)( (custom_distribution(rng) - LOW) / gap )]++;
for (int i = 0; i < xCount.size(); ++i)
{
std::cout << std::setw(2) << i << ":" << xCount[i] << "\t";
for (int bar = xCount[i]/15; bar--; std::cout << '*');
std::cout << "\n";
}
}
0:17 *
1:135 *********
2:305 ********************
3:604 ****************************************
4:859 *********************************************************
5:1106 *************************************************************************
6:1256 ***********************************************************************************
7:1353 ******************************************************************************************
8:1271 ************************************************************************************
9:1102 *************************************************************************
10:876 **********************************************************
11:614 ****************************************
12:334 **********************
13:143 *********
14:25 *