c++小知识2_随机数和概率


c++中常用的随机函数

1.低性能随机函数

  详见博客:https://blog.youkuaiyun.com/sinat_41909065/article/details/82960361
  低性能的随机函数rand()是基于LCG算法实现的,LCG随机数产生器算法可以描述为:X(n+1)=(a*X(n)+c)%m,其中种子就是X(0)的值,当a、c、m固定的情况下改变X(0)就可以改变随机序列,srand()函数就是起到这个作用,time()函数则是辅助srand()函数产生种子的。相关的函数和作用如下表所示。

函数名称作用
int rand(void)返回0~RAND_MAX(32767)的整数,伪随机函数,返回值随种子变化而变化,默认种子为1,种子不变产生的随机序列不变
void srand(unsigned int seed)设置rand()函数的种子,参数不同设置的种子不同
time(NULL)函数会返回1970年1月1日至今所经历的时间(以秒为单位),需要引入头文件<time.h>,用时间值做种子,就可以产生随机数了,因为时间总是在变的

2.高性能随机函数

  相较于古老的rand()函数,c++11提供的mt19937随机数生成器具有更好的性能,其是基于Mersenne Twister算法实现的,有兴趣的可以自行了解,这里仅介绍mt19937随机数生成器的用法。
  先给出官方文档中给出的例子:

#include <iostream>
#include <random>
 
using namespace std;
 
int main()
{
    mt19937 mt_rand(time(0));    //创建mt19937对象,并利用time(0)作为随时间变化的种子
 	for(int i=0;i<10;i++)
    	cout << mt_rand() << endl;  //输出随机数的值,由于time(0)随时间变化,因此每次的运行结果产生的随机数都不同。
    return 0;
}

  如果想要输出特定范围内的随机数,可以用以下方法:

mt19937::result_type seed = time(0);
auto dice_rand = std::bind(std::uniform_int_distribution<int>(1,6),mt19937(seed));
//uniform_int_distribution<int>(1,6):根据[1,6]区间内的均匀分布产生随机数
mt19937::result_type seed = time(0);
auto real_rand = std::bind(std::uniform_real_distribution<double>(0,1),mt19937(seed)); 
//uniform_real_distribution<double>(0,1):根据[0,1)区间内的均匀分布产生随机数

  在第一个例子中dice_rand()将输出一个[1,6]范围内的整数,在第二个例子中real_rand将会输出一个[0,1)范围内的double类型的数。需要注意的是std::bind包含在头文件#include 中。
  且uniform_int_distribution和uniform_double_distribution均可改成其他的概率分布函数。也可单独使用这些分布,具体看后面的例子。

  此外当你不想使用time(0)来设置种子时,可以用如下方法来设置种子,需要注意的是chrono包含于头文件中,因此使用时需要加上#include 。

//用流逝的时间(秒)得到一个种子
auto seed = chrono::high_resolution_clock::now().time_since_epoch().count();
mt19937 mt_rand(seed);

综合例子:

#include <iostream>
#include <random>
#include <chrono>

using namespace std ;

int main(int argc ,  char *argv[] )
{
    unsigned seed = chrono::high_resolution_clock::now().time_since_epoch().count() ;
    mt19937 rand_generator(seed) ;
    uniform_int_distribution<int> dist(6,666) ;
    for(int cnt = 0 ; cnt < 10 ; ++cnt) cout << dist(rand_generator) << endl ;
    return 0 ;
}

3.leetcode随机数实例

题目描述: 给定圆的半径和圆心的 x、y 坐标,写一个在圆中产生均匀随机点的函数 randPoint 。

说明:

  1. 输入值和输出值都将是浮点数。
  2. 圆的半径和圆心的 x、y 坐标将作为参数传递给类的构造函数。
  3. 圆周上的点也认为是在圆中。
  4. randPoint 返回一个包含随机点的x坐标和y坐标的大小为2的数组。

  解题(注:此为在leetcode编辑器上编写,如要写在常用的IDE上需要稍作修改):

class Solution {
public:
    Solution(double radius, double x_center, double y_center) {
        m_radius=radius;
        m_x_center=x_center;
        m_y_center=y_center;
    }
    
    vector<double> randPoint() {
        vector<double> VecRandPoint(2);
        double x_min=m_x_center-m_radius;
        double x_max=m_x_center+m_radius;
        double y_min=m_y_center-m_radius;
        double y_max=m_y_center+m_radius;

        mt19937::result_type seed1 = chrono::high_resolution_clock::now().time_since_epoch().count();
        mt19937::result_type seed2 = chrono::high_resolution_clock::now().time_since_epoch().count();
        double x=x_min-10;
        double y=y_min-10;
        auto real_rand_x = std::bind(std::uniform_real_distribution<double>(x_min,x_max),mt19937(seed1));
        auto real_rand_y = std::bind(std::uniform_real_distribution<double>(y_min,y_max),mt19937(seed2));
        while(sqrt((x-m_x_center)*(x-m_x_center)+(y-m_y_center)*(y-m_y_center))>m_radius)
        {
            x=real_rand_x();
            y=real_rand_y();
        }
        VecRandPoint[0]=x;
        VecRandPoint[1]=y;
        return VecRandPoint;
    }

private:
    double m_radius;
    double m_x_center;
    double m_y_center;
};

/**
 * Your Solution object will be instantiated and called as such:
 * Solution* obj = new Solution(radius, x_center, y_center);
 * vector<double> param_1 = obj->randPoint();
 */
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值