1、简介
计算机的随机数都是由伪随机数,即是由小M多项式序列生成的,其中产生每个小序列都有一个初始值,即随机种子。(注意: 小M多项式序列的周期是65535,即每次利用一个随机种子生成的随机数的周期是65535,当你取得65535个随机数后它们又重复出现了。)
伪随机数是用确定性的算法计算出来自[0,1]均匀分布的随机数序列。并不真正的随机,但具有类似于随机数的统计特征,如均匀性、独立性等。在计算伪随机数时,若使用的初值(种子)不变,那么伪随机数的数序也不变。
伪随机数可以用计算机大量生成,在模拟研究中为了提高模拟效率,一般采用伪随机数代替真正的随机数。模拟中使用的一般是循环周期极长并能通过随机数检验的伪随机数,以保证计算结果的随机性。
2、windows随机数
2.1 随机数范围计算公式
产生一定范围随机数的通用表示公式是:
要取得[0,n) 就是rand()%n 表示 从0到n-1的数
要取得[a,b)的随机整数,使用(rand() % (b-a))+ a;
要取得[a,b]的随机整数,使用(rand() % (b-a+1))+ a;
要取得(a,b]的随机整数,使用(rand() % (b-a))+ a + 1;
通用公式:a + rand() % n;其中的a是起始值,n是整数的范围。
要取得a到b之间的随机整数,另一种表示:a + (int)b * rand() / (RAND_MAX + 1)。
要取得0~1之间的浮点数,可以使用rand() / double(RAND_MAX)。
2.2 rand()
rand()会返回一随机数值, 范围在0至RAND_MAX 间。RAND_MAX定义在stdlib.h, 其值为2147483647。
#include <iostream>
#include <cstdlib>
using namespace std;
int main()
{
for (int i = 0; i < 10000; i++)
{
cout << rand()%100<< " ";
}
return 0;
}
2.3 srand()
srand()可用来设置rand()产生随机数时的随机数种子。通过设置不同的种子,我们可以获取不同的随机数序列。可以利用srand((int)(time(NULL))的方法,利用系统时钟,产生不同的随机数种子。不过要调用time(),需要加入头文件< ctime >。
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand((int)time(0)); // 产生随机种子 把0换成NULL也可以
for (int i = 0; i < 10000; i++)
{
cout << rand()%100<< " ";
}
return 0;
}
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
srand(time(nullptr)); // 用当前时间作为种子
int min = 5, max = 10;
int randomValue = (rand() % (max - min)) + min;//范围[min,max)
randomValue = (rand() % (max - min + 1)) + min;//范围[min,max]
randomValue = (rand() % (max - min)) + min + 1;//范围(min,max]
}
2.4 c++11 <random>
https://en.cppreference.com/w/cpp/numeric/random
C++标准建议使用<random>代替rand()。 <random>(since C++11) <random>中定义了随机数生成引擎、随机数分布律、不确定随机数和预定义的最佳算法实践。
2.4.1 随机数生成引擎
<random>提供了三种引擎,使用哪种需要权衡:
- linear_congruential_engine(线性同余随机数引擎):速度比较快,储存很少的中间变量。
- mersenne_twister_engine(梅森旋转随机数引擎):比较慢,占用存储空间较大,但是在参数设置合理的情况下,可生成最长的不重复序列,且具有良好的频谱特征。
- subtract_with_carry_engine(带进位随机数引擎):速度最快,占用存储空间较大,频谱特性有时不佳。
上面的三种随机数生成算法均是模板类,需要我们自己进行实例化;模板类实例化需要的参数,均是算法中使用的参数,若是不懂其原理,建议不要使用这些模板类。不过不用担心,在C++11标准中,已经帮我们预先定义了一些随机数类(预定义算法),它们都是用过上面的三个类模板实例化出来的。
2.4.2 随机数分布律
可以预先定义随机数分布的概率分布,如正态分布uniform_int_distribution、伯努利分布binomial_distribution、泊松分布poisson_distribution等等。
2.4.3 预定义算法
定义了算法的最佳实践,避免了参数的选择,可以直接选择引擎,设定分布规律就好。算法包括minstd_rand0、minstd_rand、mt19937、mt19937_64、ranlux24_base、ranlux48_base等。
类名称 | 属性 | 依赖类 |
---|---|---|
linear_congruential_engine | templates | \ |
mersenne_twister_engine | templates | \ |
subtract_with_carry_engine | templates | \ |
discard_block_engine | Engine adaptors | \ |
independent_bits_engine | Engine adaptors | \ |
shuffle_order_engine | Engine adaptors | \ |
default_random_engine | instantiations | 待定 |
minstd_rand | instantiations | linear_congruential_engine |
minstd_rand0 | instantiations | linear_congruential_engine |
mt19937 | instantiations | mersenne_twister_engine |
mt19937_64 | instantiations | mersenne_twister_engine |
ranlux24_base | instantiations | subtract_with_carry_engine |
ranlux48_base | instantiations | subtract_with_carry_engine |
ranlux24 | instantiations | ranlux24_base、discard_block_engine |
ranlux48 | instantiations | ranlux48_base、discard_block_engine |
knuth_b | instantiations | shuffle_order_engine |
2.4.4 random_device
random_device是标准库提供的一个非确定性随机数生成设备,是所有生成器中唯一一个不需要随机数种子的方式。在Linux中,是需要读取/dev/urandom设备。需要注意的是random_device在某些操作系统中是无法使用的,会在构造函数或者调用operator()函数时抛出异常,因此在进行代码移植时,需要格外注意。
2.4.5 实现代码
#include <random>
using namespace std;
int main(){
int min = 0,max = 100;
random_device seed;//硬件生成随机数种子
ranlux48 engine(seed());//利用种子生成随机数引擎
uniform_int_distribution<> distrib(min, max);//设置随机数范围,并为均匀分布
int random = distrib(engine);//随机数
}
#include <iostream>
#include <random>
int main(int argc, char**argv){
std::default_random_engine engine;
for (int i = 0; i < 10; ++i ){
std::cout << engine() << " ";
}
std::cout << std::endl;
return 0;
}
3、linux随机数
3.1 简介
/dev/random 和 /dev/urandom /dev/urandom 是一个伪随机数生成器,缺乏熵它也不会停止。 /dev/random 是一个真随机数生成器,它会在缺乏熵的时候停止。
3.4.3 std::random_device
C++ 中也提供了真随机数 random_device。它在 Windows 下调用 rand_s,在 Linux 下调用 /dev/urandom。真随机数的优点是足够随机,但它会消耗很多系统资源,在某些情况下是不可接受的。在真随机数的生成里,把随机数的生成分成两个部分,第一个部分称之为熵生成,指的就是前面说的各类噪声,第二部分就是熵提取,指的就是把噪声数据进行变化。
#include <iostream>
#include <random>
double getRandomDevice()
{
std::random_device rd;
std::mt19937 mt(rd());
return (unsigned int)mt();
}
结语
如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;
╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地
//(ㄒoㄒ)//,就在评论处留言,作者继续改进;
o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;
(✿◡‿◡)
感谢各位大佬童鞋们的支持!
( ´ ▽´ )ノ ( ´ ▽´)っ!!!