需求

我们通过调查,得知大多数人在20岁左右初恋,以20岁为基准,以随机变量X表示早于或晚于该时间的年数,为了简单,假设X值域为[-5,5],并且PDF(X)是一个正态分布函数(当然可以为任意分布,这里具体化一个熟悉的,方便后面验证)

现在要求,做出一个计算机模拟程序,该程序能算出一系列X的值,并且这些值是符合观测所得的PDF(X)的

困难:

1.我们不可能有现成的函数,能够直接生成一系列值并且符合该分布。(虽然例子中指定了正态分布,但现实情况是任何分布都有可能,所以即使C++支持一系列分布函数,也不能解决本质问题)

2.难以求得一个函数的逆函数(至少我不知道怎么求。。至于为什么要求这个,下面会解释)

思路

1.得到一个均匀分布的,值域为[0,1]之间的随机函数并不困难,linux环境下有drand48()可用,windows下可借助于rand()实现;假设随机数为 r

2.可由PDF(X)得到CDF(X)

3.CDF(X)的值域是[0,1],CDF-1(X)的定义域是[0,1],如果我们可以得到CDF的逆函数,就可以直接通过该函数得到想要的结果

3.将CDF的定义域,也就是[-5,5],分成32段,定义为一个数组,假设数组名为cdfs,得到cdfs长度为33 ,其中cdfs[0] = 0,cdfs[32]=1

4.找到cdfs(i),使得cdfs(i)是升序排列后找到的,大于等于r的cdfs数组中的最小值,如果没有找到的话,就返回cdfs(32),也就是1

5.假设找到的i = 15,此时情况如下图

显然我们只需要知道AC的长度即可得到随机变量X的取值,假设该值为x,则 x = A点的横坐标 + AC的长度

由于A点是第15个点,所以 x = -5 + (10/32)*15 + AC

而由于 AC / AD = RC / BD,所以 AC = RC * AD / BD

其中,RC = r - cdfs[15] , AD = B点横坐标 -  A点横坐标,也就是一个dx的长度,即 (10/32),BD = B点纵坐标 - A点纵坐标 = cdfs[16] - cdfs[15]

这样就得出x了

大体思路就是如此,以下是简陋的代码实现,C++基本属于不会用,后面会持续改进这个例子

  1. #include <iostream>
  2. #include <random>
  3. #define M_PI 3.14159265358979323846
  4.  
  5. using namespace std;
  6.  
  7. // 产生0~1之间的随机数
  8. double randx() {
  9. random_device rd;
  10. default_random_engine gen{ rd() };
  11. uniform_real_distribution<> distr;
  12. return distr(gen);
  13. }
  14.  
  15. // standard normal distribution function
  16. float pdf(const float& x)
  17. {
  18. return / sqrtf( * M_PI) * exp(-x * x * 0.5);
  19. }
  20.  
  21. // create CDF
  22. // nbins 将cdf分成多少段
  23. // minBound 下限
  24. // maxBound 上限
  25. float* cdfCreator(const int nbins, float minBound, float maxBound) {
  26.  
  27. // cdf容量是要比nbin多1的;试想如果nbins=2,也就是说把[-5,5]分成2段,结果对CDF来说形成了3个节点,分别是-5,0,5
  28. //float cdf[nbins + 1], dx = (maxBound - minBound) / nbins, sum = 0;
  29. float* cdf = new float[nbins + ];
  30. float dx = (maxBound - minBound) / nbins;
  31. cdf[] = ;
  32. cdf[nbins] = ;
  33. for (int n = ; n < nbins; n++) {
  34. float x = minBound + (maxBound - minBound) * (n / (float)(nbins));
  35. // 计算dx这一小块对应的概率
  36. float pdf_x = pdf(x) * dx;
  37. cdf[n] = cdf[n - ] + pdf_x;
  38. }
  39.  
  40. // 调试信息
  41. cout << "[DEBUG] cdf: ";
  42. for (int i = ; i < ; i++) {
  43. cout << "cdf[" << i << "]: " << cdf[i] << endl;
  44. }
  45.  
  46. return cdf;
  47. }
  48.  
  49. float sample(float* cdf, const uint32_t & nbins, const float& minBound, const float& maxBound)
  50. {
  51. float r = randx();
  52. float dx = (maxBound - minBound) / nbins;
  53.  
  54. // 从cdf开始,到cdf+nbins+1为止,找到第一个大于或等于r的值,在这个例子中,cdf+nbins=32,也就是cdf[32],即cdf数组的最后一个元素
  55. // 得到的ptr指向从cdf[0]到cdf[32]中随机的一个元素的地址
  56. // 由于后买计算bd时用到了off+1,为了不越界,所以off最大只能为31,所以ptr最大能取第cdf[31]的地址,所以下面要-1
  57. float* ptr = std::lower_bound(cdf, cdf + nbins - , r);
  58.  
  59. // 由于lower_bound的性质,cdf[ptr-cdf]永远是大于r的,为了符合我们上文的构思,这里就进行减一处理,对应于上图,off是15而不是16
  60. int off = ptr - cdf - ;
  61.  
  62. float rc = r - cdf[off];
  63. float ad = dx;
  64. float bd = cdf[off + ] - cdf[off];
  65. float ac = rc * ad / bd;
  66. float x = minBound + dx * off + ac;
  67. return x;
  68. }
  69.  
  70. int main(int argc, char** argv)
  71. {
  72. // create CDF
  73. const int nbins = ;
  74. float minBound = -, maxBound = ;
  75. float* cdf = cdfCreator(nbins, minBound, maxBound);
  76.  
  77. // our simulation
  78. int numSims = ; //样本容量10万
  79. const int numBins = ; // to collect data on our sim
  80. int bins[numBins]; // to collect data on our sim
  81. memset(bins, 0x0, sizeof(int) * numBins); // set all the bins to 0 ,将bins的前sizeof(int)*numBins个字节全部设置值为0x0
  82.  
  83. for (int i = ; i < numSims; i++) { // 抽样十万
  84. float x = sample(cdf, nbins, minBound, maxBound); // random var between -5 and 5
  85.  
  86. //计算x落在了我们自己定义的哪个分段里
  87. int whichBin = (int)((numBins - ) * (x - minBound) / (maxBound - minBound));
  88. bins[whichBin]++;
  89. }
  90.  
  91. // 输出bins看看对不对
  92. for (int i = ; i < numBins; i++) {
  93. /*float r = bins[i] / (float)numSims;
  94. printf("%f %f\n", 5 * (2 * (i / (float)(numBins)) - 1), r);
  95. cout << "[debug]i: " << i << endl;*/
  96. cout << "bins[" << i << "]: " << bins[i] << endl;
  97. }
  98.  
  99. delete cdf;
  100. return ;
  101. }

运行结果:像是那么回事

  1. bins[0]: 0
  2. bins[1]: 0
  3. bins[2]: 1
  4. bins[3]: 0
  5. bins[4]: 0
  6. bins[5]: 0
  7. bins[6]: 2
  8. bins[7]: 0
  9. bins[8]: 1
  10. bins[9]: 2
  11. bins[10]: 5
  12. bins[11]: 7
  13. bins[12]: 6
  14. bins[13]: 7
  15. bins[14]: 13
  16. bins[15]: 28
  17. bins[16]: 34
  18. bins[17]: 34
  19. bins[18]: 52
  20. bins[19]: 95
  21. bins[20]: 92
  22. bins[21]: 92
  23. bins[22]: 166
  24. bins[23]: 163
  25. bins[24]: 239
  26. bins[25]: 391
  27. bins[26]: 366
  28. bins[27]: 426
  29. bins[28]: 705
  30. bins[29]: 724
  31. bins[30]: 719
  32. bins[31]: 1200
  33. bins[32]: 1150
  34. bins[33]: 1191
  35. bins[34]: 1793
  36. bins[35]: 1861
  37. bins[36]: 1916
  38. bins[37]: 2504
  39. bins[38]: 2557
  40. bins[39]: 2630
  41. bins[40]: 3243
  42. bins[41]: 3278
  43. bins[42]: 3316
  44. bins[43]: 3811
  45. bins[44]: 3896
  46. bins[45]: 3857
  47. bins[46]: 3811
  48. bins[47]: 4013
  49. bins[48]: 4150
  50. bins[49]: 3827
  51. bins[50]: 3830
  52. bins[51]: 3803
  53. bins[52]: 3542
  54. bins[53]: 3287
  55. bins[54]: 3315
  56. bins[55]: 3029
  57. bins[56]: 2618
  58. bins[57]: 2590
  59. bins[58]: 2474
  60. bins[59]: 1882
  61. bins[60]: 1832
  62. bins[61]: 1735
  63. bins[62]: 1171
  64. bins[63]: 1176
  65. bins[64]: 1191
  66. bins[65]: 722
  67. bins[66]: 705
  68. bins[67]: 665
  69. bins[68]: 379
  70. bins[69]: 321
  71. bins[70]: 382
  72. bins[71]: 213
  73. bins[72]: 185
  74. bins[73]: 164
  75. bins[74]: 97
  76. bins[75]: 88
  77. bins[76]: 75
  78. bins[77]: 39
  79. bins[78]: 30
  80. bins[79]: 33
  81. bins[80]: 21
  82. bins[81]: 7
  83. bins[82]: 6
  84. bins[83]: 7
  85. bins[84]: 3
  86. bins[85]: 3
  87. bins[86]: 3
  88. bins[87]: 1
  89. bins[88]: 0
  90. bins[89]: 2
  91. bins[90]: 0
  92. bins[91]: 0
  93. bins[92]: 0
  94. bins[93]: 0
  95. bins[94]: 0
  96. bins[95]: 0
  97. bins[96]: 0
  98. bins[97]: 0
  99. bins[98]: 0
  100. bins[99]: 0

【图形学手记】Inverse Transform Sampling 逆转换抽样的更多相关文章

  1. 【图形学手记】law of the unconscious statistician

    以扔色子为例,结果集为{1,2,3,4,5,6},每个数字出现的概率为1/6 以色子结果为随机变量X,如果我们定义函数F(X) = (X-3)2,我们来计算F(X)的概率分布: X=1,F(1)=(1 ...

  2. Pseudo Random Nubmer Sampling

    Pseudo Random Nubmer Sampling https://en.wikipedia.org/wiki/Inverse\_transform\_sampling given a dis ...

  3. 从随机过程到马尔科夫链蒙特卡洛方法(MCMC)

    从随机过程到马尔科夫链蒙特卡洛方法 1. Introduction 第一次接触到 Markov Chain Monte Carlo (MCMC) 是在 theano 的 deep learning t ...

  4. MCMC and Bayesian Data Analysis(PPT在文件模块)

    How to generate a sample from $p(x)$? Let's first see how Matlab samples from a $p(x)$. In Matlab, t ...

  5. Direct2D教程VI——转换(Transform)

    目前博客园中成系列的Direct2D的教程有 1.万一的 Direct2D 系列,用的是Delphi 2009 2.zdd的 Direct2D 系列,用的是VS中的C++ 3.本文所在的 Direct ...

  6. 随机抽样问题(蓄水池问题Reservoir Sampling)

    转自:孤影醉残阳 http://hi.baidu.com/siyupy/item/e4bb218fedf4a0864414cfad 随机抽样问题(蓄水池问题Reservoir Sampling) 随即 ...

  7. 其实 Gradle Transform 就是个纸老虎 —— Gradle 系列(4)

    前言 目前,使用 AGP Transform API 进行字节码插桩已经非常普遍了,例如 Booster.神策等框架中都有 Transform 的影子.Transform 听起来很高大上,其本质就是一 ...

  8. 集显也能硬件编码:Intel SDK && 各种音视频编解码学习详解

    http://blog.sina.com.cn/s/blog_4155bb1d0100soq9.html INTEL MEDIA SDK是INTEL推出的基于其内建显示核心的编解码技术,我们在播放高清 ...

  9. 我的Android进阶之旅------>Android中编解码学习笔记

    编解码学习笔记(一):基本概念 媒体业务是网络的主要业务之间.尤其移动互联网业务的兴起,在运营商和应用开发商中,媒体业务份量极重,其中媒体的编解码服务涉及需求分析.应用开发.释放license收费等等 ...

随机推荐

  1. idea运行web项目乱码

    windows下idea中web项目乱码,主要原因是服务器端乱码(执行webservlet的时候,编码格式改变),导致客户端的编码格式与webservlet传递过的编码格式不一致. 前端网页的编码,通 ...

  2. vs code 保存显示无法写入文件的解决方法

    右键文件夹点击属性 选择安全 把当前用户权限都勾选上就可以了

  3. java 枚举的用法

    public enum StatisticTableEnum { DOC_BROWSE_STATISTIC("doc_browse_statistic"), DOC_LIB_BRO ...

  4. Linux双网口配置时重复配置DEFROUTE和GATEWAY

    配置一台机器时,沿袭了原有网口配置,修改网口名,把em1全部修改改为eth0 mv ifcfg-em1 ifcfg-eth0 mv ifcfg-em2 ifcfg-eth1 改完以后,机器变得不稳定, ...

  5. JAVA笔记3-this关键字

    1.          2.例题

  6. Java架构师面试题——JVM性能调优

    JVM内存调优 对JVM内存的系统级的调优主要的目的是减少GC的频率和Full GC的次数. 1.Full GC 会对整个堆进行整理,包括Young.Tenured和Perm.Full GC因为需要对 ...

  7. jquery isDefaultPrevented()方法 语法

    jquery isDefaultPrevented()方法 语法 作用:isDefaultPrevented() 方法返回指定的 event 对象上是否调用了 preventDefault() 方法. ...

  8. Unity3D_(插件)使用Camera渲染制作Minimap小地图

    制作小地图:使用Camera渲染出来Render Texture 原理:使用摄像机从上到下获得场景游戏物体,摄像机Culling Mask渲染层级可设置是否需要在小地图上展示游戏物体,将摄像机获得的场 ...

  9. gulp自动化构建工具安装使用(1)

    我用的是windows,所以以下操作针对于windows用户,其他系统有不一样的地方请自行查阅资料更正. 好了,废话少说,反正也就是随手捣腾.下雨了,天晴了,我们开始搞gulp了 安装:gulp是个构 ...

  10. 20175212童皓桢 《Java程序设计》第十周学习总结

    学号 2016-2017-2 <Java程序设计>第X周学习总结 教材学习内容总结 一.Java中的线程的状态 建的线程在它的一个完整的生命周期中通常要经历如下的四种状态: 1.新建: 当 ...