RNG 函数 C++

Posted

技术标签:

【中文标题】RNG 函数 C++【英文标题】:RNG function C++ 【发布时间】:2019-06-03 23:01:11 【问题描述】:

我正在尝试用 C++ 编写一个函数,该函数每次返回一个介于 0 和 1 之间的随机浮点/双精度值,每次都具有不同的值。

我尝试了几种不同的 srand、rand 和 RAND_MAX 方向,但每次运行代码时,每次都应该更改的某些值具有恒定值。我有一个术语,即 x = 20 * randomnumber() 但每次它都会为 x 返回相同的值。无论我多久运行一次代码。这是我的功能。

double randomnumber()

    srand(time(NULL))
    double r1 = ((double)rand()) / RAND_MAX);

    return r1;

我想要它做的是生成一个介于 0 和 1 之间的浮点数,这样当我乘以另一个整数时,我会得到一个介于 0 和该整数之间的值。注意:我知道有一个函数可以在 0 和数字之间显式执行此操作,但我正在编写的代码最好每次都乘以一个随机数。

提前致谢。

【问题讨论】:

std::uniform_real_distribution<>(0.0,1.0)? 警告:使用rand() is highly problematic,我们强烈建议您使用合适的random number generator facility in the Standard Library,以产生高质量的随机值。您使用time(NULL) 作为随机数种子意味着如果在同一秒内运行,这将产生相同的结果,并且在许多平台上rand()barely random at all。 理论上,如果我将其更改为此处所述的均匀真实分布,它会解决问题吗? --挖掘漫画顺便说一句 在这里查看why you should call srand() only once。 不幸的是,这个帖子上有很多关于 RNG 好坏的噪音。但很可能最大的问题是@CostantinoGrana 指出的问题:您应该只在程序开始时调用srand() 一次,而不是每次在您的方法中。即使您使用更好的 PRNG,按照您的方式播种仍然会破坏它的随机性。 【参考方案1】:

最好的方法是使用 C++ 的随机数库,不是rand()

我们可以很容易地做到这一点:

#include <random>

double randomnumber() 
    // Making rng static ensures that it stays the same
    // Between different invocations of the function
    static std::default_random_engine rng;

    std::uniform_real_distribution<double> dist(0.0, 1.0); 
    return dist(rng); 

这将每次生成一个新的随机数,并且每次运行程序时都会生成相同的随机数序列。如果我运行

int main() 
    for(int i = 0; i < 10; i++) 
        std::cout << randomnumber() << '\n'; 
    

那我看看

0.131538
0.45865
0.218959
0.678865
0.934693
0.519416
0.0345721
0.5297
0.00769819
0.0668422

随机初始化生成器。如果您想在每次运行程序时生成不同的随机数,则必须使用随机种子初始化生成器。生成一个非常容易:

auto getRandomSeed() 
    -> std::seed_seq

    // This gets a source of actual, honest-to-god randomness
    std::random_device source;

    // Here, we fill an array of random data from the source
    unsigned int random_data[10];
    for(auto& elem : random_data) 
        elem = source(); 
    

    // this creates the random seed sequence out of the random data
    return std::seed_seq(random_data + 0, random_data + 10); 

一旦我们有了这个种子,我们就可以修改randomnumber() 来创建带有随机种子的生成器:

#include <random>

double randomnumber() 
    // Making rng static ensures that it stays the same
    // Between different invocations of the function
    static auto seed = getRandomSeed(); 
    static std::default_random_engine rng(seed);

    std::uniform_real_distribution<double> dist(0.0, 1.0); 
    return dist(rng); 

【讨论】:

【参考方案2】:

您的代码中一切正常 - 也许您对结果进行了取整而没有注意到更改。运行程序在第 4 位小数后依次变化双倍。 在我的平台中,从 time(...) 返回的 time_t 正在缩小转换为 unsigned int - 检查这一点。并且种子生成器一次就足够了 - 不是每个 randomnumber() 调用。您写道,您将结果用于蒙特卡罗模拟 - 生产中的蒙特卡罗模拟需要高质量的随机数 - 而不是 rand() 可能产生的。

#include <stdlib.h>     /* srand, rand */
#include <time.h>       /* time */
#include <iostream>

double randomnumber()

    double r1 = (double)rand() / RAND_MAX;

    return r1;


int main()

    srand(time(NULL));
    std::cout << randomnumber() << std::endl;

【讨论】:

以上是关于RNG 函数 C++的主要内容,如果未能解决你的问题,请参考以下文章

传递一个并行安全的 RNG 来运行

gsl_rng_default 未解决的外部错误

深度解密 Go math/rand

[吃药深度学习随笔] 练习:训练二次方程的参数

获取 Usedrange 的函数出现错误 91

如何正确结束基本功能