如何从C++;? 如何从C++中生成0到1之间的随机双均匀分布?
当然,我能想到一些答案,但我想知道标准做法是什么:如何从C++;? 如何从C++中生成0到1之间的随机双均匀分布?,c++,random,C++,Random,当然,我能想到一些答案,但我想知道标准做法是什么: 良好的标准遵从性 良好的随机性 好速度 (对于我的应用程序来说,速度比随机性更重要) 非常感谢 PS:如果这很重要,我的目标平台是Linux和Windows。一个老式的解决方案,如: double X=((double)rand()/(double)RAND_MAX); 应满足您的所有标准(便携、标准和快速)。 显然,必须对生成的随机数进行播种。标准程序如下: srand((unsigned)time(NULL)); 来自的是您所需要的
- 良好的标准遵从性
- 良好的随机性
- 好速度
PS:如果这很重要,我的目标平台是Linux和Windows。一个老式的解决方案,如:
double X=((double)rand()/(double)RAND_MAX);
应满足您的所有标准(便携、标准和快速)。
显然,必须对生成的随机数进行播种。标准程序如下:
srand((unsigned)time(NULL));
来自的是您所需要的。您可以尝试Mersenne Twister算法
它很好地融合了速度和随机性,并且有一个GPL实现。如果速度是您最关心的问题,那么我只想使用它
double r = (double)rand() / (double)RAND_MAX;
考虑到简单性和速度是您的主要标准,您可以添加一个小型通用帮助器,如下所示:-
// C++ rand generates random numbers between 0 and RAND_MAX. This is quite a big range
// Normally one would want the generated random number within a range to be really
// useful. So the arguments have default values which can be overridden by the caller
int nextRandomNum(int low = 0, int high = 100) const {
int range = (high - low) + 1;
// this modulo operation does not generate a truly uniformly distributed random number
// in the span (since in most cases lower numbers are slightly more likely),
// but it is generally a good approximation for short spans. Use it if essential
//int res = ( std::rand() % high + low );
int res = low + static_cast<int>( ( range * std::rand() / ( RAND_MAX + 1.0) ) );
return res;
}
<代码> //C++ + rand在0和随机数之间生成随机数,这是一个相当大的范围。
//通常,人们希望生成的随机数在一个范围内是真实的
//有用。因此,参数具有可由调用方重写的默认值
int nextRandomNum(int low=0,int high=100)常量{
整数范围=(高-低)+1;
//这种模运算不会产生真正均匀分布的随机数
//在跨度内(因为在大多数情况下,较低的数字更可能出现),
//但对于短跨度来说,它通常是一个很好的近似值。如果必要,可以使用它
//int res=(标准::兰德()%高+低);
int res=low+static_cast((范围*std::rand()/(rand_MAX+1.0));
返回res;
}
随机数生成是一个研究得很好、很复杂且很高级的课题。除了其他答案中提到的算法外,您可以在此处找到一些简单但有用的算法:-
以下是您在使用时的操作方法 没有
double X=((double)rand()/(double)rand_MAX)那么快代码>,但具有更好的分布。该算法只提供RAND_MAX等间距的返回值选择;这一个给出了RANDMAX^6,所以它的分布仅受double的精度限制
如果您想要一个长的双精度,只需添加一些迭代。如果您想在[0,1]中输入一个数字,而不是[0,1],只需将第4行读取为out=(double)rand()/(rand_MAX);
//返回范围(0.0f,1.0f)内的随机数。
// 0111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
//见EEEEEEEEEEVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVV
//符号='s'
//指数='e'
//值='v'
双双兰德(){
typedef无符号长uint64;
uint64 ret=0;
对于(int i=0;i<13;i++){
在C++ 11和C++ 14中,RET=((UTIT64)(RAND())16)< P> >。Stephan T. Lavavej的介绍解释了为什么我们不应该在C++中使用<代码> RAND()/<代码>,以支持<代码> Read 标头,并进一步加强这一点。
下面的示例是cppreference站点上示例代码的修改版本,使用引擎和生成[0,1)
范围()中的数字:
既然帖子提到速度是重要的,那么我们应该考虑描述不同随机数引擎(强调雷)的CP优惠部分:
选择要使用的引擎涉及到许多权衡*:
**线性同余引擎速度适中,并且具有非常小的
状态的存储要求。滞后斐波那契发生器
即使在没有高级算术指令的处理器上,速度也非常快
设置,但牺牲了更大的状态存储,有时甚至更少
理想的光谱特性。梅森捻线机速度较慢且
具有更高的状态存储要求,但参数正确
具有最长的非重复序列和最理想的
光谱特性(对于给定的理想定义)
因此,如果有一个更快的发电机的愿望,也许有更好的选择
兰德()
如果您被迫使用rand()
,那么关于的指南的C FAQ为我们提供了一个类似于此的示例,用于生成间隔[0,1)
:
C++11标准库包含一个像样的框架和两个可维护的生成器,这对于家庭作业和即兴使用来说已经足够了
但是,对于生产级代码,在使用之前,您应该确切地知道各种发电机的具体特性,因为它们都有自己的警告。此外,它们都没有通过诸如TestU01之类的PRNG标准测试,除非使用了大量奢侈因素的ranlux发电机
如果你想要可靠的、可重复的结果,那么你必须带上你自己的生成器
如果你想要便携性,那么你必须带上自己的发电机
如果您可以在受限的可移植性下生活,那么您可以将boost或C++11框架与您自己的生成器结合使用
更详细的信息-包括一个简单但快速的生成器的代码,具有卓越的质量和丰富的链接-可以在我对类似主题的回答中找到:
对于专业统一浮点偏差,还有两个问题需要考虑:
- 打开与半打开与关闭范围,即(0,1),[0,1]或[0,1]
- 从整数到浮点的转换方法(精度、速度)
两者实际上是同一枚硬币的两面,因为转换方法考虑了0和1的包含/排除
double randDouble()
{
double out;
out = (double)rand()/(RAND_MAX + 1); //each iteration produces a number in [0, 1)
out = (rand() + out)/RAND_MAX;
out = (rand() + out)/RAND_MAX;
out = (rand() + out)/RAND_MAX;
out = (rand() + out)/RAND_MAX;
out = (rand() + out)/RAND_MAX;
return out;
}
//Returns a random number in the range (0.0f, 1.0f).
// 0111 1111 1111 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
// seee eeee eeee vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv vvvv
// sign = 's'
// exponent = 'e'
// value = 'v'
double DoubleRand() {
typedef unsigned long long uint64;
uint64 ret = 0;
for (int i = 0; i < 13; i++) {
ret |= ((uint64) (rand() % 16) << i * 4);
}
if (ret == 0) {
return rand() % 2 ? 1.0f : 0.0f;
}
uint64 retb = ret;
unsigned int exp = 0x3ff;
retb = ret | ((uint64) exp << 52);
double *tmp = (double*) &retb;
double retval = *tmp;
while (retval > 1.0f || retval < 0.0f) {
retval = *(tmp = (double*) &(retb = ret | ((uint64) (exp--) << 52)));
}
if (rand() % 2) {
retval -= 0.5f;
}
return retval;
}
#include <iostream>
#include <iomanip>
#include <map>
#include <random>
int main()
{
std::random_device rd;
std::mt19937 e2(rd());
std::uniform_real_distribution<> dist(0, 1);
std::map<int, int> hist;
for (int n = 0; n < 10000; ++n) {
++hist[std::round(dist(e2))];
}
for (auto p : hist) {
std::cout << std::fixed << std::setprecision(1) << std::setw(2)
<< p.first << ' ' << std::string(p.second/200, '*') << '\n';
}
}
0 ************************
1 *************************
#include <stdlib.h>
double randZeroToOne()
{
return rand() / (RAND_MAX + 1.);
}
double randMToN(double M, double N)
{
return M + (rand() / ( RAND_MAX / (N-M) ) ) ;
}
double rand_easy(void)
{ return (double) rand() / (RAND_MAX + 1.0);
}
double rand_safe(void)
{
double limit = pow(2.0, DBL_MANT_DIG);
double denom = RAND_MAX + 1.0;
double denom_to_k = 1.0;
double numer = 0.0;
for ( ; denom_to_k < limit; denom_to_k *= denom )
numer += rand() * denom_to_k;
double result = numer / denom_to_k;
if (result == 1.0)
result -= DBL_EPSILON/2;
assert(result != 1.0);
return result;
}
#define RANDMAX (-1ULL)
uint64_t custom_lcg(uint_fast64_t* next)
{ return *next = *next * 2862933555777941757ULL + 3037000493ULL;
}
uint_fast64_t internal_next;
void seed_fast(uint64_t seed)
{ internal_next = seed;
}
double rand_fast(void)
{
#define SHR_BIT (64 - (DBL_MANT_DIG-1))
union {
double f; uint64_t i;
} u;
u.f = 1.0;
u.i = u.i | (custom_lcg(&internal_next) >> SHR_BIT);
return u.f - 1.0;
}
double rand_dist(double min, double max)
{ return rand_fast() * (max - min) + min;
}
double rand_open(void)
{ return rand_dist(DBL_EPSILON, 1.0);
}
double rand_closed(void)
{ return rand_dist(0.0, 1.0 + DBL_EPSILON);
}
#include<stdlib.h>
double randomDouble() {
double lowerRange = 1.0;
double upperRange = 10.0;
return ((double)rand() * (upperRange - lowerRange)) / (double)RAND_MAX + lowerRange;
}
int range_upper_bound = 12345;
int random_number =((double)rand()/(double)range_upper_bound);