如何生成大量高质量的随机数?

时间:2014-09-26 05:29:00

标签: c++ c++11 random scientific-computing

我正在研究在格子中移动的粒子的随机游走模拟。出于这个原因,我必须创建大量的随机数,大约10 ^ 12及以上。目前,我正在使用C ++ 11提供<random>的可能性。在分析我的程序时,我发现<random>花费了大量时间。绝大多数这些数字在0到1之间,均匀分布。在这里,我需要一个二项分布的数字。但重点在于0..1数字。

问题是:如何减少生成这些数字所需的CPU时间以及对其质量有何影响?

正如您所看到的,我尝试了不同的引擎,但这对CPU时间没有太大影响。此外,我的uniform01(gen)generate_canonical<double,numeric_limits<double>::digits>(gen)无论如何有什么区别?

编辑:通过阅读答案,我得出的结论是,我的问题没有理想的解决方案。因此,我决定首先使我的程序具有多线程功能,并在不同的线程中运行多个RNG(以一个random_device编号+一个线程单独增量播种)。目前这种接缝是最不可避免的步骤(无论如何都需要多线程)。作为进一步的步骤,等待确切的要求,我考虑切换到建议的英特尔RNG或Thrust。这意味着我的RNG实现不应该是复杂的,当前不是。但是现在我喜欢专注于我的模型的物理正确性,而不是编程的东西,只要我的程序输出在物理上是正确的。 Thrust Concerning Intel RNG

以下是我目前所做的事情:

class Generator {
public:
    Generator();
    virtual ~Generator();
    double rand01(); //random number [0,1)
    int binomial(int n, double p); //binomial distribution with n samples with probability p
private:
    std::random_device randev; //seed
    /*Engines*/
    std::mt19937_64 gen;
    //std::mt19937 gen;
    //std::default_random_engine gen;
    /*Distributions*/
    std::uniform_real_distribution<double> uniform01;
    std::binomial_distribution<> binomialdist;
};

Generator::Generator() : randev(), gen(randev()), uniform01(0.,1.), binomial(1,1.) {
}

Generator::~Generator() { }

double Generator::rand01() {
    //return uniform01(gen);
    return generate_canonical<double,numeric_limits<double>::digits>(gen);
}

int Generator::binomialdist(int n, double p) {
    binomial.param(binomial_distribution<>::param_type(n,p));
    return binomial(gen);
}

5 个答案:

答案 0 :(得分:3)

您可以预处理随机数并在需要时使用它们。

如果您需要真正的随机数,我建议您使用像http://www.random.org/这样的服务来确保通过环境环境计算的随机数而不是某些算法。

而且,谈到随机数,您还必须检查:

enter image description here

答案 1 :(得分:1)

如果您需要大量的随机数,我的意思是MASSIVE,请在互联网上仔细搜索IBM的浮点随机数生成器,这可能是十年前发布的。您必须购买PowerPC机器或带有融合乘法附加功能的新型Intel机器。他们以每个核心每个周期一个的速率获得随机数。因此,如果您购买了新的Mac Pro,您每秒可能会获得大约500亿个随机数。

答案 2 :(得分:1)

也许不是使用CPU而是可以使用GPU同时生成多个数字?

http://http.developer.nvidia.com/GPUGems3/gpugems3_ch37.html

答案 3 :(得分:0)

在我的i3上,以下程序在大约五秒内运行:

#include <random>
std::mt19937_64 foo;

double drand() {
  union {
    double d;
    long long l;
  } x;
  x.d = 1.0;
  x.l |= foo() & (1LL<<53)-1;
  return x.d-1;
}

int main() {
  double d;
  for (int i = 0; i < 1e9; i++)
    d += drand();
  printf("%g\n", d);
}

而将drand()调用替换为以下结果导致程序在大约十秒内运行:

double drand2() {
  return std::generate_canonical<double,
      std::numeric_limits<double>::digits>(foo);
}

使用以下代替drand()也会导致程序在大约十秒内运行:

std::uniform_real_distribution<double> uni;
double drand3() {
  return uni(foo);
}

上面的hacky drand()可能比标准解决方案更适合您的目的..

答案 4 :(得分:-2)

任务定义

OP要求获得

的答案

<强> 1。生成速度 - 假设一组10E+012随机数为&#34; 大量&#34;

<强> 2。生成器的质量 - 假设数字在一定范围内均匀分布的假设也是随机的

然而,有更多的基本方面需要解决并成功解决实际系统:

A. 定义,是否需要为系统模拟提供保证重复性的随机数序列,以便将来重新运行实验

如果不是这种情况,重新运行模拟实验将主要产生不同的结果,然后随机数发生器过程(或预随机化器和随机选择器)不必担心它们的重新生成 - 中,完全运行的操作模式,实现起来会更简单。

B。定义生成的随机数证明随机性所需的级别(或生成的随机数集必须属于哪个级别)一些特定的统计理论定律(一些已知的合成分布或真正随机的,随机数集的最大Kolmogorov复杂度))。人们不需要NSA专家来说明真随机序列的数值生成器是一个非常棘手的问题,并且它具有与高随机性产品的生成相关的计算成本。

超混沌和真随机序列在计算上非常昂贵。对于随机性质量敏感的应用程序而言,使用低或差随机生成器不是一种选择(无论市场营销论文如何说,没有MIL-STD或NSA级别的系统会在环境中尝试这种受损的质量,其结果确实很重要那么为什么要在科学模拟中少花钱?如果你不介意错过这么多未模拟的模拟现象状态,也许不是问题。

C. 验证您的模拟系统需要多少随机数&#34;根据[usec]消耗多少随机数&#34;以及这个设计要求参数是否是常量,或者可以通过进入多线程,矢量化,基于网格/云的分布式计算框架来扩大规模。

D。在矢量化或网格/云的情况下,您的模拟系统是否需要维护全局或每线程或perGrid / CloudNode-个体访问管理到随机数池的计算策略。

任务解决方案方法

解决了[A]和[B]的

最快 [1]和最佳 [2]解决方案,[D]的选项是预生成最大随机性将质量数写入适当的访问池(并在访问策略和访问管理控制上支付可接受的[C]和[D]成本,以便从池中重新读取,而不是重新生成)。