我的博客和笔记我的博客和笔记
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
首页
文章
  • TurboLink
  • TinyEncrypt
  • UnrealStyleGuide
  • AxTrace
  • Cyclone
  • 数学相关
  • 图形学
  • 密码学
  • 编程语言
关于
GitHub
  • 我的文章

    • 从抛币协议到智能合约

      • Part1
      • Part2
    • JPEG算法解密

      • Part1
      • Part2
      • Part3
      • Part4
      • Part5
      • Github
    • SPH算法简介

      • Part1
      • Part2
      • Part3
      • Part4
      • Github
    • 赌博中的数学:Martingle策略
    • 如何生成一个随机的圆形
    • 一个简单的DH密钥协商算法的实现
    • 如何计算线段和圆的交点
    • 一道数学趣题
    • 斐波那契数列和1/89
    • 匀速贝塞尔曲线运动的实现

      • Part1
      • Part2
  • 开源项目

    • TurboLink
    • TinyEncrypt
    • UnrealStyleGuide
    • AxTrace
    • Cyclone
  • 学习笔记

    • 数学相关

      • 常用数学符号
      • 群
      • 数论(一)
      • 数论(二)
      • 数论(三)
      • 概率
    • 密码学

      • RSA
      • 抛币协议
      • 智能扑克协议
    • 图形学

      • 数学基础

        • 矢量
        • 矩阵
        • 立体角
        • 几何变换(一)
        • 几何变换(二)
        • 法线变换
        • 摄像机变换
      • 光照模型

        • 传统光照模型
        • 光度学
        • 双向反射分布函数(BRDF)
        • 微平面理论(一)
        • 微平面理论(二)
        • 微平面理论(三)
        • 光照方程
      • 环境光渲染

        • 环境光渲染(一)
        • 环境光渲染(二)
    • 编程语言

      • JavaScript

        • 环境搭建
        • 基本语法
        • 函数
        • 对象和类

如何生成一个随机的圆形

最近在工作中遇到这么一个问题:

在游戏场景中有一个怪物生成点,这个生长点产生的怪物均匀分布在半径为R的圆形内,这个随机算法应该如何生成?看起来很简单,随手写了一个:

#define RAND  ((float)rand()/RAND_MAX)
 
void get_random_pos(float center_x, float center_y, float radius, float&x, float& y)
{
    float u = RAND*radius;
    float v = RAND*2*PI;
    
    x = center_x + u*cos(v);
    y = center_y + u*sin(v);
}

但写的过程中,直觉告诉我,这么写肯定是有问题的,试想,如果以北京为例,如果北京的人口是均匀分布的,那么如果让所有人都报出自己家和天安门的距离,那么这些数据肯定不是均匀,因为居住在五环附近的人数肯定要大于居住在二环附近的人数,于是用Mathamatica实验一下:

果然,这么写是不对的,网上查了一下,这个问题还真是有人研究过,说应该把所获得的随机数开平方一下,实验一下:

但是,这个开平方背后的数学原理究竟是什么呢?抽空翻了下概率书,原来,其中的道理并不复杂,这里涉及到概率里的一个基本概念,累计分布函数(Cumulative distribution function),简称CFD,它的定义如下: 设有一个随机变量X,它的取值范围是从负无穷到正无穷,如果把它的值小于x的概率表达为一个函数F(x),那么这个函数就称为X的累计分布函数

F(x)=P(X≤x)

以最为常见的均匀分布概率为例,设均匀分布的随机变量X的取值范围是[a,b],那么它的累计分布函数以及函数图像是

F(x)={0x<ax−ab−aa≤x<b1b≤x

对于一个累计分布函数,符合以下规律

  • 0≤F(x)≤1
  • F(x)单调递增
  • limx→−∞F(x)=0,limx→+∞F(x)=1

回到我们的问题中,假设怪物产生的范围的半径为R,随机产生一只怪物时,它和中心的距离是一个随机变量X,显然,对于怪物均匀分布的情况,X落在半径为x的圆内的概率,等于半径为x小圆和半径为X的大圆的面积之比

也就是说

F(x)=P(X≤x)=x2/R2

现在我们手头上只有均匀概率的随机数产生器,要想产生这么个随机数需要用到一个很巧妙的运算,就是反函数。设随机变量u是一个均匀分布在[0,1]之间的随机数,另一个随机变量X=F−1(u),现在我们需要证明X的累计分布函数是F(x)
证明如下

P(X≤x)=P(F−1(u)≤x)=P(u≤F(x))=F(x)

初看起来有点复杂,其实在下面的图上可以很直观的理解这个过程:

这是利用了F(x)是单调递增函数的特性,在我们的问题中,F(x)的反函数可以表达为

F−1(u)=Ru

所以最终的算法可以写成

#define RAND  ((float)rand()/RAND_MAX)
 
void get_random_pos(float center_x, float center_y, float radius, float&x, float& y)
{
    float u = sqrt(RAND)*radius;
    float v = RAND*2*PI;
    
    x = center_x + u*cos(v);
    y = center_y + u*sin(v);
}
Prev
赌博中的数学:Martingle策略
Next
一个简单的DH密钥协商算法的实现