正确生成随机数的两种姿势
本帖最后由 pcy190 于 2019-2-21 17:59 编辑第一次发帖,还请大佬们轻拍。
为什么不推荐用`rand()`函数,可以看看https://codeforces.com/blog/entry/61587。
# 使用**RDSEED**,**RDRAND**指令
> `RDSEED`,`RDRAND`是两个汇编指令,通过硅片上的热噪声来生成随机数。
- 从Intel Broadwell架构的 CPU 和AMD Zen架构的 CPU开始支持此指令
- 在AMD和Intel的CPU上,可以使用`CPUID`指令来检测CPU是否支持`RDRAND`指令。如果支持该指令,调用CPUID的01号标准函数之后,ECX寄存器的第30位会被设置成1。
- 从RDSEED指令获取输入流比从RDRAND获取要慢。
关于RDSEED和RDRAND指令的区别和具体工作,文献很少。笔者从INTEL官网找到了相关文章。
大意就是如果打算用来作为其它伪随机数生成器(pseudorandom number generator)的种子的时候,可以使用RDSEED,其他情况则使用RNRAND
感兴趣的读者可以戳此https://software.intel.com/en-us/blogs/2012/11/17/the-difference-between-rdrand-and-rdseed
首先检测当前CPU是否支持`RDRAND`,我们通过调用CPUID的01号标准函数,根据执行后的ECX寄存器第30位是否为1来判断。如果为1,则支持。
```
cpuid
and eax, 0x20000000 //比较第30位
test eax, 0
```
核心代码就是`rdrand eax`将生成的随机数放到`eax`寄存器中
下面是自己写的生成100个随机数生成的代码,仅供参考。
```
#include <iostream>
using namespace std;
int main()
{
bool flag = 0;
unsigned int result = 0;
__asm {
mov eax, 1
cpuid
and eax, 0x20000000 //30th bit
test eax, 0
jnz L
mov flag, 1
L:
}
if (!flag) {
cout << "Not support this CPU!";
return 0;
}
for (int i = 0; i < 100; i++) {
__asm {
rdrand eax
mov result, eax
}
cout << result << endl;
}
return 0;
}
```
# 使用mt19937
mt19937是什么?它是c++11中加入的新特性,是一种随机数算法。
总的一点,相对于传统的srand(),mt19937拥有更好的性能。
具有速度快,周期长的特点(它的名字便来自周期长度:2^19937-1)
`rand()`函数在windows下生成的数据范围为0-32767
但是这个mt19937的随机范围在(−MAXINT,+MAXINT) (其中MAXINT为int的最大值)
它的使用非常简单
```
#include<random>
#include<ctime>
std::mt19937 rnd (time(0));
int main()
{
printf("%lld\n",rnd());
return 0;
}
```
另外,random_shuffle使用的时自带的`rand()`
我们可以把`rnd`函数传入`shuffle`,使shuffle更随机
```
shuffle(a, a + n, rnd); //a为数组
```
这样就能让数组内的元素随机移动足够大的距离
关于mt19937具体可以见(http://www.cplusplus.com/reference/random/mt19937/)
总体来说,mt19937使用很方便,RDRAND作为CPU层面的随机数,具有更佳的表现。
页:
[1]