【小沐学C++】C++11 实现随机数生成(Windows、Linux)

15 篇文章 0 订阅

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

https://en.cppreference.com/w/cpp/numeric/random

C++标准建议使用代替rand()。
(since C++11)
中定义了随机数生成引擎、随机数分布律、不确定随机数和预定义的最佳算法实践。

2.4.1 随机数生成引擎

提供了三种引擎,使用哪种需要权衡:

  • 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_enginetemplates\
mersenne_twister_enginetemplates\
subtract_with_carry_enginetemplates\
discard_block_engineEngine adaptors\
independent_bits_engineEngine adaptors\
shuffle_order_engineEngine adaptors\
default_random_engineinstantiations待定
minstd_randinstantiationslinear_congruential_engine
minstd_rand0instantiationslinear_congruential_engine
mt19937instantiationsmersenne_twister_engine
mt19937_64instantiationsmersenne_twister_engine
ranlux24_baseinstantiationssubtract_with_carry_engine
ranlux48_baseinstantiationssubtract_with_carry_engine
ranlux24instantiationsranlux24_base、discard_block_engine
ranlux48instantiationsranlux48_base、discard_block_engine
knuth_binstantiationsshuffle_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.2 命令

3.2.1 /dev/random

消耗完系统熵池中熵

cat /dev/random
cat /dev/random > /dev/null &

在这里插入图片描述

当熵池中熵值小于阈值(cat /proc/sys/kernel/random/write_wakeup_threshold)时,系统会自动收集熵源数据,添加到熵池,增加熵值;当达到阈值时,系统会停止收集熵源数据,熵池中熵值不会自动继续增加。
使用 /dev/random 和 /dev/urandom 随机文件(CentOS、Ubuntu、MacOS 都支持,推荐)。
/dev/random 和 /dev/urandom 存储的都是乱码,实际上它们是通过二进制数据保存实时数据的
打开 /dev/random 和 /dev/urandom 文件,推荐用 head,不推荐 cat 命令,因为文件非常大且是乱码,只需要获取前几行文件内容就变了。用到了 cksum 命令,其读取文件内容,生成唯一的整型数据,只有文件内容没变,生成结果就不会变化,与php crc函数类似,一般校验文件是否篡改。
其生成随机数的原理是:截取文件的一部分内容,做内容的计算,取第一个数值。

head -20 /dev/urandom | cksum
head -20 /dev/urandom | cksum | cut -f1 -d " "

在这里插入图片描述

3.2.2 /proc/sys/kernel/random

  • 查看接口
ls /proc/sys/kernel/random

在这里插入图片描述

  • 查看系统熵池中拥有的熵数
    This read-only file gives the available entropy, in bits. This will be a number in the range 0 to 4096。
cat /proc/sys/kernel/random/entropy_avail

在这里插入图片描述

  • 查看熵池容量
    说明熵池的大小(以位为单位)。This file is read-only, and gives the size of the entropy pool in bits. It contains the value 4096
cat /proc/sys/kernel/random/poolsize
  • 查看从熵池中读取熵的阀值
    当 entropy_avail 中的值少于这个阀值,这读取 /dev/random 会被阻塞。
cat /proc/sys/kernel/random/read_wakeup_threshold
cat /proc/sys/kernel/random/write_wakeup_threshold
  • 产生随机字符串
    These read-only files contain random strings like 6fd5a44b-35f4-4ad4-a9b9-6b9be13e1fe9. The former is generated afresh for each read, the latter was generated once。
cat /proc/sys/kernel/random/uuid
cat /proc/sys/kernel/random/boot_id

在这里插入图片描述

3.2.3 $RANDOM

计算机产生的的只是“伪随机数”,不会产生绝对的随机数(是一种理想随机数)。实际上,伪随机数和理想随机数也是相对的概念。伪随机数在大量重现时也并不一定保持唯一,但一个好的伪随机产生算法将可以产生一个非常长的不重复的序列,例如 UUID(通用唯一识别码)在100亿年内才可用完。

使用系统的 $RANDOM 变量(CentOS、Ubuntu、MacOS 都支持,但只有5位数随机)。
$RANDOM 的范围是 [0, 32767]。

echo $RANDOM
echo $RANDOM |md5sum |cut -c 1-8  #获取8位随机字符

在这里插入图片描述
Bourne Again Shell 俗称 Bash。由于其易用和免费的特性,在日常工作中被广泛使用。除此之外,Bash 也是大多数 Linux 系统默认的 Shell。
Bash Shell脚本是用Bash编写的计算机程序,它是一个包含了自定义数量命令的纯文本文件,用于在Linux系统上自动循环执行重复性任务。
在这里插入图片描述
在这里插入图片描述

3.2.4 awk

还可以通过 awk 产生随机数,最大为6位随机数,其跟时间有关,系统时间一致则随机数都相同,据说没有 $RANDOM 随机性好。

awk 'BEGIN{srand(); print rand()}'        
awk 'BEGIN{srand(); print rand()*1000000}'

在这里插入图片描述

3.2.5 date

使用date +%s%N(CentOS、Ubuntu支持,MacOS不支持纳秒 +%N)。
通过 Linux / Unix 的时间戳来获取随机数。
如果用时间戳 date +%s 做随机数,相同一秒的数据是一样的。在做循环处理多线程时,基本不能满足要求。
如果用纳秒值 date +%N 做随机数,精度达到了亿分之一,相当精确了,在多cpu高并发的循环里,同一秒里也很难出现相同结果,不过也会有重复碰撞的可能性。
如果用时间戳+纳秒值 date +%N%s 做组合随机数(10+9=19位数),重复的概率大大降低,但注意: MacOS 系统不支持纳秒值,不算通用。

date +%S  	# 获取秒数, 2位数
date +%s 	# 获取时间戳, 10位数, 从 1970-01-01 00:00:00 到当前的间隔的秒数
date +%N 	# 获取纳秒值, 9位数, CentOS、Ubuntu支持, 但 MacOS 不支持

# 使用date 生成随机字符串
date +%s%N | md5sum | head -c 10

#获取8位随机数字
date +%N | cut -c 1-8   

# 使用 /dev/urandom 生成随机字符串
cat /dev/urandom | head -n 10 | md5sum | head -c 10

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.2.5 uuid

使用 linux uuid (CentOS、Ubuntu支持,MacOS不支持。

  • UUID(Universally Unique Identifier,通用唯一识别码),格式包含32个16进制数字,以’-'连接号分为5段。格式为 8-4-4-4-12 的32个字符,例如: 07e73165-1196-4194-98bb-a3bf7c96e34a。
  • UUID 数量:理论上的总数为216 x 8=2128,约等于3.4 x 1038。 也就是说若每奈秒产生1兆个UUID,要花100亿年才会将所有UUID用完。
  • UUID 目的:是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与其它人冲突的 UUID。在这样的情况下,就不需考虑数据库创建时的名称重复问题。它会让网络任何一台计算机所生成的uuid码,都是互联网整个服务器网络中唯一的。它的原信息会加入硬件,时间,机器当前运行信息等等。
  • UUID 格式:包含32个16进位数字,以“-”连接号分为五段,形式为8-4-4-4-12的32个字符。范例;550e8400-e29b-41d4-a716-446655440000,所以与 uuid类似的还有一个guid(全局唯一标识符)码,它由微软支持,它们由操作系统内核产生。
cat /proc/sys/kernel/random/uuid
head -n 20 /proc/sys/kernel/random/uuid | cksum | cut -f1 -d ' '
cat /proc/sys/kernel/random/uuid |cut -c 1-8   #获取8位随机字符

在这里插入图片描述

3.2.6 openssl

使用 openssl rand (CentOS、Ubuntu支持、MacOS 都支持,需安装 openssl,推荐)。
openssl rand 用于产生指定长度个bytes的随机字符。
结合 cksum 产生整数、md5sum 产生字符串,可以产生随机的整数或字符串(仅含小写字母和数字)。

openssl rand -base64 8						# 第1次执行
openssl rand -base64 8 | cksum				# 生成随机整数
openssl rand -base64 8 | md5sum 			# 生成随机字符串
openssl rand -base64 8 | cksum | cut -c1-8	# 截取数字
openssl rand -base64 8 | md5sum | cut -c1-8 	# 截取字符串
openssl rand -hex 8
openssl rand -hex 8 | cksum                 # 生成随机整数
openssl rand -hex 8 | md5sum                # 生成随机字符串
openssl rand -hex 8 | cksum | cut -c1-8	    # 截取数字
openssl rand -hex 8 | md5sum | cut -c1-8 	# 截取字符串

openssl rand -base64 6   #获取8位随机字符
openssl rand -base64 9   #获取12位随机字符
openssl rand -base64 8 | cksum |cut -c 1-8  #获取8位随机数字

在这里插入图片描述

3.2.7 Haveged

Haveged 是一个守护进程,它使用处理器的“抖动”将熵添加到系统熵池中。

  • 安装haveged:
# CentOS 7 yum install rng-tools haveged -y 
# Debian 9 apt install rng-tools haveged -y

在这里插入图片描述

  • 启动haveged并开机启动,并查看haveged状态:
systemctl start haveged                    #启动
systemctl enable haveged                   #开机启动
systemctl restart haveged                  #重新启动
systemctl status haveged                   #查看启动状态
systemctl list-unit-files | grep haveged    #查看开机启动状态

在这里插入图片描述
在这里插入图片描述

#rng-tools
systemctl enable rng-tools 
systemctl status rng-tools
#systemctl start rng-tools
service rngd start

在这里插入图片描述

sudo apt install pv
pv /dev/random > /dev/null 

在这里插入图片描述

使用 pv 我们可以看到我们通过管道传递了多少数据。正如你所看到的,在运行 haveged 之前,我们是 2.1 位/秒(B/s)。而在开始运行 haveged 之后,加入处理器的抖动到我们的熵池中,我们得到大约 1.5MiB/秒。
在这里插入图片描述

3.3 函数

3.3.1 random

https://www.zx2c4.com/projects/linux-rng-5.17-5.18/
https://git.kernel.org/pub/scm/linux/kernel/git/crng/random.git/tree/drivers/char/random.c
在这里插入图片描述

3.3.2 ioctl

The following ioctl(2) requests are defined on file descriptors connected to either /dev/random or /dev/urandom. All requests performed will interact with the input entropy pool impacting both /dev/random and /dev/urandom. The CAP_SYS_ADMIN capability is required for all requests except RNDGETENTCNT.

The character special files /dev/random and /dev/urandom (present since Linux 1.3.30) provide an interface to the kernel’s random number generator. The file /dev/random has major device number 1 and minor device number 8. The file /dev/urandom has major device number 1 and minor device number 9.

#include <linux/random.h>
int ioctl(fd, RNDrequest, param);
   RNDGETENTCNT
          Retrieve the entropy count of the input pool, the contents
          will be the same as the entropy_avail file under proc.
          The result will be stored in the int pointed to by the
          argument.

   RNDADDTOENTCNT
          Increment or decrement the entropy count of the input pool
          by the value pointed to by the argument.

   RNDGETPOOL
          Removed in Linux 2.6.9.

   RNDADDENTROPY
          Add some additional entropy to the input pool,
          incrementing the entropy count.  This differs from writing
          to /dev/random or /dev/urandom, which only adds some data
          but does not increment the entropy count.  The following
          structure is used:

              struct rand_pool_info {
                  int    entropy_count;
                  int    buf_size;
                  __u32  buf[0];
              };

          Here entropy_count is the value added to (or subtracted
          from) the entropy count, and buf is the buffer of size
          buf_size which gets added to the entropy pool.

   RNDZAPENTCNT, RNDCLEARPOOL
          Zero the entropy count of all pools and add some system
          data (such as wall clock) to the pools.

3.3.3 /proc

The files in the directory /proc/sys/kernel/random (present since 2.3.16) provide additional information about the /dev/random device:

entropy_avail
          This read-only file gives the available entropy, in bits.
          This will be a number in the range 0 to 4096.

   poolsize
          This file gives the size of the entropy pool.  The
          semantics of this file vary across kernel versions:

          Linux 2.4:
                 This file gives the size of the entropy pool in
                 bytes.  Normally, this file will have the value
                 512, but it is writable, and can be changed to any
                 value for which an algorithm is available.  The
                 choices are 32, 64, 128, 256, 512, 1024, or 2048.

          Linux 2.6 and later:
                 This file is read-only, and gives the size of the
                 entropy pool in bits.  It contains the value 4096.

   read_wakeup_threshold
          This file contains the number of bits of entropy required
          for waking up processes that sleep waiting for entropy
          from /dev/random.  The default is 64.

   write_wakeup_threshold
          This file contains the number of bits of entropy below
          which we wake up processes that do a select(2) or poll(2)
          for write access to /dev/random.  These values can be
          changed by writing to the files.

   uuid and boot_id
          These read-only files contain random strings like
          6fd5a44b-35f4-4ad4-a9b9-6b9be13e1fe9.  The former is
          generated afresh for each read, the latter was generated
          once.

3.4 Linux代码示例

3.4.1 gcc编译

那么,到底如何分步编译 C、C++ 程序呢?事实上,GCC 编译器除了提供 gcc 和 g++ 这 2 个指令之外,还提供有大量的指令选项,方便用户根据自己的需求自定义编译方式。在前面的学习过程中,我们已经使用了一些指令选项,比如编译 C++ 程序时 gcc 指令后跟的 -xc++、-lstdc++、-shared-libgcc,再比如手动指定可执行文件名称的 -o 选项。

注意,虽然我们仅编写了一条 gcc 或者 g++ 指令,但其底层依据是按照预处理、编译、汇编、链接的过程将 C 、C++ 程序转变为可执行程序的。而本应在预处理阶段、编译阶段、汇编阶段生成的中间文件,此执行方式默认是不会生成的,只会生成最终的 a.out 可执行文件(除非为 gcc 或者 g++ 额外添加 -save-temps 选项)。

gcc/g++指令选项功 能
-E(大写)预处理指定的源文件,不进行编译。
-S(大写)编译指定的源文件,但是不进行汇编。
-c编译、汇编指定的源文件,但是不进行链接。
-o指定生成文件的文件名。
-llibrary(-I library)其中 library 表示要搜索的库文件的名称。该选项用于手动指定链接环节中程序可以调用的库文件。建议 -l 和库文件名之间不使用空格,比如 -lstdc++。
-ansi对于 C 语言程序来说,其等价于 -std=c90;对于 C++ 程序来说,其等价于 -std=c++98。
-std=手动指令编程语言所遵循的标准,例如 c89、c90、c++98、c++11 等。

当然,gcc 指令也为用户提供了“手动指定代表编译方式”的接口,即使用 -x 选项。例如,gcc -xc xxx 表示以编译 C 语言代码的方式编译 xxx 文件;而 gcc -xc++ xxx 则表示以编译 C++ 代码的方式编译 xxx 文件。

## 如果想使用 gcc 指令来编译执行 C++ 程序,需要在使用 gcc 指令时,手动为其添加 -lstdc++ -shared-libgcc 选项,表示 gcc 在编译 C++ 程序时可以链接必要的 C++ 标准库。
## gcc -xc++ demo.cpp -lstdc++ -shared-libgcc
g++ demo.cpp  #或者 gcc -xc++ -lstdc++ -shared-libgcc demo.cpp
./a.out

## 将 main.c 和 func.c 两个源文件编译成一个可执行文件,其名字为 app.out。
## 如果不使用 -o 选项,那么将生成名字为 a.out 的可执行文件。
gcc main.c func.c -o app.out

## GCC一次编译多文件项目
gcc myfun.c main.c -o main.exe
./main.exe
#or
gcc -c myfun.c main.c
gcc myfun.o main.o -o main.exe
./main.exe
#or
gcc *.c -o main.exe
./main.exe

## GCC 编译器无法找到 cos() 这个函数。为了编译这个 main.c,必须使用-l选项,以链接数学库:
## 数学库的文件名是 libm.a。前缀lib和后缀.a是标准的,m是基本名称,GCC 会在-l选项后紧跟着的基本名称的基础上自动添加这些前缀、后缀,本例中,基本名称为 m。
## 在支持动态链接的系统上,GCC 自动使用在 Darwin 上的共享链接库 libm.so 或 libm.dylib。
gcc main.c -o main.out -lm

## (1)把链接库作为一般的目标文件,为 GCC 指定该链接库的完整路径与文件名。
## 如果链接库名为 libm.a,并且位于 /usr/lib 目录,那么下面的命令会让 GCC 编译 main.c,然后将 libm.a 链接到 main.o:
gcc main.c -o main.out /usr/lib/libm.a

## (2)使用-L选项,为 GCC 增加另一个搜索链接库的目录:
## 可以使用多个-L选项,或者在一个-L选项内使用冒号分割的路径列表。
gcc main.c -o main.out -L/usr/lib -lm

## (3)把包括所需链接库的目录加到环境变量 LIBRARYPATH 中。
  • -Wall选项
    使gcc产生尽可能多的警告信息,警告信息很有可能是错误的来源,特别是隐式编程错误,所以尽量保持0 warning。

  • -Werror 选项
    要求gcc将所有的警告当作错误进行处理。

  • -fPIC选项
    PIC指Position Independent Code。共享库要求有此选项,以便实现动态连接(dynamic linking)。

  • -I 选项(大写的 i)
    向头文件搜索目录中添加新的目录。
    1、用#include"file"的时候,gcc/g++会先在当前目录查找你所制定的头文件,如
    果没有找到,他回到缺省的头文件目录找。
    如果使用-I制定了目录,他会先在你所制定的目录查找,然后再按常规的顺序去找.
    2、用#include,gcc/g++会到-I制定的目录查找,查找不到,然后将到系统的缺
    省的头文件目录查找
    例如:gcc –I /usr/dev/mysql/include test.c –o test.o

  • -l选项(小写的 l)
    说明库文件的名字。如果库文件为 libtest.so, 则选项为: -ltest

  • -L选项
    说明库文件所在的路径。
    例如:-L.(“.”表示当前路径)。 -L/usr/lib (“/usr/lib” 为路径。注:这里的路径是绝对路径)
    如果没有提供 -L选项,gcc 将在默认库文件路径下搜索

  • -shared选项指定生成动态连接库,不用该标志外部程序无法连接。相当于一个可执行文件, 生成 .so 文件

  • -static 选项,强制使用静态链接库,生成 .a 文件。因为gcc在链接时优先选择动态链接库,只有当动态链接库不存在时才使用静态链接库。加上该选项可强制使用静态链接库。
    .so 和 .a 的区别:运行时动态加载,编译时静态加载

3.4.2 g++编译

g++ filename.cpp
g++ filename.cpp -o filename

g++ -c 1.cpp -o 1.o
g++ -c 2.cpp -o 2.o
g++ 1.o 2.o -o out

g++ -o filename filename.cpp
g++ -o filename file1.cpp file2.cpp

g++ hello.cpp -fPIC -shared -o libworld.so
g++ hello.cpp -o world

3.4.3 std::random_device

真随机数利用某些自然因素(如熵)的随机性生成。Linux 中的 /dev/random 生成的就是真随机数。
伪随机数则利用一些生成算法来产生。通常来讲,C++ 中生成的随机数就是伪随机数。

  • (1)LCG
    rand() 利用的是线性同余法(LCG)生成伪随机数。LCG 的优势在于速度快、占用内存小。但是由于其不够随机,所以并不能把它用在蒙特卡洛之类的算法上。
  • (2)RANLUX
    ranlux 本质上还是 LCG,不过它使用的是带进位减法(Subtract-With-Carry)。显然,等级越高,随机数越难以被预测。综合考虑性能等因素,3 级在现实中使用较多。
  • (3)梅森旋转(Mersenne Twister - C++ 中的 mt1993)也是一种伪随机数生成方法,不过可以生成比 LCG 质量高得多的随机数。MT 得名于其周期为梅森素数。其利用的是 LFSR(更准确地讲,是 GFSR)。
  • (4)C++ 中也提供了真随机数 random_device。它在 Windows 下调用 rand_s,在 Linux 下调用 /dev/urandom。真随机数的优点是足够随机,但它会消耗很多系统资源,在某些情况下是不可接受的。在真随机数的生成里,把随机数的生成分成两个部分,第一个部分称之为熵生成,指的就是前面说的各类噪声,第二部分就是熵提取,指的就是把噪声数据进行变化。

真随机数发生器(TRNG):是指利用物理方法实现的随机数发生器。它是自然界随机的物理过程(所产物理现象的不确定性)的反映,即使算法等TRNG的所有信息都被暴露,都无法猜测其结果,即高质量的真随机数发生器产生的随机数永远不具备周期性。这就使其在本质上区别于广泛应用的伪随机数发生器(PRNG),伪随机数发生器是基于数学算法的随机数发生器,它由真随机的种子和伪随机网络构成。

伪随机数生成器(PRNG):是由冯诺依曼在 1946 年创造的。他的基本思想是从一个随机数种子开始,对其平方,然后取中间值。接下来重复对得到的数取平方并取中间值的过程,就会得到一个具有统计意义属性的随机数序列了。这也就是广为人知的平方取中法。然而,冯诺依曼的方法并没有经得住时间的考验,因为不论从什么随机种子开始,序列最终都会落入某个短循环序列,比如:8100,6100,4100,8100,6100,4100……。1949 年,数学家 D.H.Lehmer 利用线性同余生成器(LCG)实现了这一思路。下面给出的是基于 Lehmer 的方法所实现的一种朴素 PRNG,叫做中央随机数生成器,使用 JavaScript 在 1995 年写的。

#include <iostream>
#include <random>
double getRandomDevice()
{
	std::random_device rd;
	std::mt19937 mt(rd());
	return (unsigned int)mt();
}

在这里插入图片描述

结语

如果您觉得该方法或代码有一点点用处,可以给作者点个赞,或打赏杯咖啡;╮( ̄▽ ̄)╭
如果您感觉方法或代码不咋地//(ㄒoㄒ)//,就在评论处留言,作者继续改进;o_O???
如果您需要相关功能的代码定制化开发,可以留言私信作者;(✿◡‿◡)
感谢各位大佬童鞋们的支持!( ´ ▽´ )ノ ( ´ ▽´)っ!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值