新旧C++生成随机浮点数方法,你喜欢哪个?

点击蓝字

805f4e868778602fdffe7df5a53bf545.png

关注我们

一、在C++11之前,我们通常采用rand函数来生成随机数。

有时我们想用rand生成一组随机数,即使我们调用了srand,但生成的还是相同值。为什么会产生这种情况?又该如何解决?下面将用第一视角一起探究这其中的奥秘。

场景描述:

想生成一组整形随机数,放入数组中,用来测试自己的排序是否正确。

于是我写出了下方代码,生成随机数。

先简单了解下用到的函数:

//返回time_t类型的 当前时间的时间戳
time_t time (time_t* timer);


//传入一个种子,为伪随机数生成器初始化
void srand (unsigned int seed);


//得到一个整形伪随机数
int rand (void);
#include <stdio.h>
#include <time.h>
#include <stdlib.h>


int main()
{
    int arr[10] = { 0 };


    for (int i = 0; i < 10; ++i)
    {
        srand((unsigned int)time(NULL));
        //两个相减是为了出现负的随机数,使测试范围更广
        arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);


        printf("%d ", arr[i]);
    }


    return 0;
}

我发现尽管我调用了srand函数,可生成的数组值还是同一个。我思考后想到,因为for循环执行速度太快,整个程序都是在一秒内完成的。所以出现了都是同一个值的情况。

初步解决

于是我想出了下面的解决方法:

我可以在for循环内调用Sleep函数,让我的电脑休眠一下,这样就不会出现上述情况了。

于是我写出了下方的代码:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <windows.h>




int main()
{
    int arr[10] = { 0 };


    for (int i = 0; i < 10; ++i)
    {
        Sleep(1000);
        srand((unsigned int)time(NULL));
        arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);


        printf("%d ", arr[i]);
    }


    return 0;
}

通过休眠后,就成功解决问题了。可是,

如果睡眠时间太短,那么还是会出现重复的现象;

如果睡眠时间太长,程序运行速度就太慢。

最终方法

因为上述的原因,又详细了解了一下rand和srand的基本原理,最终成功解决了该问题。

给srand函数传入一个数值后,srand会根据这个生成一个随机序列表(通常有4,294,967,296个数),传入相同的数生成的序列表是相同的。然后rand从序列的头部取出一个数返回,然后将这个数放在随机序列表尾部,因此如果你要取的数据量非常大,是会出现与之前取出的数重复的情况。

此时,上面出现的问题也很好解决了。因为计算机运行速度很快,所以我们每次进入循环都会生成一个相同的随机序列表,rand函数只会取出其第一个数。

要解决这个问题,我们只需要在循环前调用一次srand函数就好了,这样就不会重复生成序列表了。

下方是最终形式的代码:

#include <stdio.h>
#include <time.h>
#include <stdlib.h>


int main()
{
    int arr[10] = { 0 };


    srand((unsigned int)time(NULL));
    for (int i = 0; i < 10; ++i)
    {
        arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);


        printf("%d ", arr[i]);
    }


    return 0;
}

但rand函数对一些情况显得难以处理:

  • 不同范围的随机数

  • 需要随机浮点数

  • 需要非均匀分布的随机数

二、C++11定义在头文件random中的随机数库

下文将使用C++11定义在头文件random中的随机数库通过一组协作的类来解决这些问题:随机数引擎类和随机数分布类。

  • 一个引擎类可以生成unsigned随机数序列

  • 一个分布类使用一个引擎类生成指定类型的、在给定范围内的、服从特定概率分布的随机数

1、生成等概率随机数

生成随机整数

uniform_int_distribution:产生均匀分布的整数

template <class IntType = int> 
class uniform_int_distribution;


// IntType
// An integer type. Aliased as member type result_type.
// By default, this is int.
#include <iostream>
#include <random>
#include <ctime>
using namespace std;


int main()
{
    //产生[1, 100]左闭右闭区间的随机整数
  uniform_int_distribution<int> u(1, 100);
  default_random_engine e;
    //为随机数引擎设置随机种子,若不设置每次生成的随机数相同(可以创建时设置)
    //类似srand的用法,相同的种子生成的随机数相同
    //default_random_engine e(time(NULL));
    e.seed(time(NULL));


  for (size_t i = 0; i < 10; ++i)
  {
    cout << u(e) << " ";
  }
  cout << endl;


  return 0;
}

生成随机浮点数

uniform_real_distribution:产生均匀分布的实数

template <class RealType = double> 
class uniform_real_distribution;


// RealType
// A floating-point type. Aliased as member type result_type.
// By default, this is double.
#include <iostream>
#include <random>
#include <ctime>
using namespace std;


int main()
{
    //生成[-1, 1]范围随机浮点数
    //模板参数只能是浮点类型(float,double, long double)
  uniform_real_distribution<double> u(-1, 1);
    default_random_engine e(time(NULL));


  for (size_t i = 0; i < 10; ++i)
  {
    cout << u(e) << " ";
  }
  cout << endl;


  return 0;
}

2、生成非均匀分布随机数


正态分布随机数

template <class RealType = double> 
class normal_distribution;
#include <iostream>
#include <random>
#include <ctime>
using namespace std;


int main()
{
//生成符合均值为10,标准差为2的随机数
  normal_distribution<double> u(10, 2);
default_random_engine e(time(NULL));


for (size_t i = 1; i <= 100; ++i)
  {
printf("%-9.6lf ", u(e));
if (i % 10 == 0)
    {
cout << endl;
    }
  }
cout << endl;


return 0;
}

二项分布的布尔值

class bernoulli_distribution;
#include <iostream>
#include <random>
#include <ctime>
using namespace std;


int main()
{
// 生成1的概率为0.7
bernoulli_distribution u(0.7); 
default_random_engine e(time(NULL));


for (int i = 0; i < 10; i++) {
cout << u(e) << " ";
  }
cout << endl;


return 0;
}

简单分享,快乐学习,如有错误请多包涵!

*声明:本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

941bdacdd565ec106c86a5a905be61d3.png

6a7a9d8c665a8f6cb78681111ef2fd03.gif

戳“阅读原文”我们一起进步

  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值