【问题标题】:Uniform random number generator in closed interval闭区间均匀随机数发生器
【发布时间】:2014-02-07 15:04:51
【问题描述】:

我需要一个用于 c 或 c++ 的无偏均匀随机数生成器(双精度),在 闭合 区间上,例如 [0,1]。

许多随机数生成器,例如 GSL gsl_rng_uniform(r),只能在开放区间内工作,如 [0,1),但这不适合我的情况。

阿尔。

【问题讨论】:

  • 整数还是浮点数?
  • 定义“好”均匀随机数生成器...除了“闭区间”,您还需要哪些其他属性?你打算如何使用它?
  • 还有为什么 CC++ 可以选择一个,它们不一样,答案也不一样。
  • 在 [0,1] 中得到任何实数的概率为零。因此,在 [0,1] 或 [0,1) 中取实数在数学上是接近的。唯一的区别是“1”的情况,但它的发生概率无论如何都是空的。
  • 为了扩展 @ndj 所说的内容,恰好在间隔结束时获得随机 double 的机会介于 2^54 中的 1 和 2^64 中的 1 之间。生成足够多的随机数来注意开区间和闭区间之间的差异是不切实际的。

标签: c++ c random gsl


【解决方案1】:

除非您有整数值,否则闭区间的概念有问题 - 因为到达区间“结束”的概率非常小。如果你有一个最大值为RAND_MAX的整数随机数生成器,那么你通过计算得到一个闭区间

rand() / double(RAND_MAX)

因为它会精确地从 0 变为 1(含)

如果这不能为您提供足够的分辨率,您可以考虑“连接”多个随机数。鉴于 double 实际上具有 53 位的尾数(加上一位“始终为 1”),您可以这样做(此代码假定 RAND_MAX = 0xFFFFFFFF 以提高可读性;您可以对其进行改进...):

#include <stdio.h>
#include <stdlib.h>

double goodRand() {
  unsigned long long r;
  unsigned long long int r1, r2;
  r1 = rand();
  r2 = rand();
  r = (r1 << 22) + (r2 & 0x003FFFFF);
  return (double) r/ (double)(0x001FFFFFFFFFFFFF);
}

int main(void) {
  int i;
  double rMax = 0;
  for (i =0; i < 10000; i++) {
    double temp;
    temp = goodRand();
    rMax = (temp>rMax)?temp:rMax;
  }
  printf("max value is %lf\n", rMax);
}

现在您已经有了非常精细的随机数采样,最大值为 1.0(含)。您可以使代码更紧凑,但这是一般的想法...

【讨论】:

  • 听起来很有趣!我读到 c 函数 rand() 产生的数字非常相关,即不是很随机。我可以使用(double)gsl_rng_uniform_int (r, N)/(double)(N-1) 之类的东西并使用N 调整精度吗? GSL 的文档是:link
  • 你是对的 - 在某些实现中,rand() 的低位经过循环模式,这使得它“不那么随机”。这就是为什么指定随机性对您意味着什么很重要的原因。您可以调整上述技巧以掩盖随机数的低 12 位并重复 3 次 - 这消除了所有“稍微非随机”的数字。还有其他随机数生成器库。我试图说明的一点是:您的要求是可以精确地生成1.00000,因为只有从整数 PRNG 开始才能满足数字;在实践中重要吗?
【解决方案2】:

C++11 Random 怎么样,例如 std::mt19937 + std::uniform_int_distribution?

std::mt19937 generator;
std::uniform_int_distribution<int> distribution(0,1);
int number = distribution(generator);

【讨论】:

  • 我非常怀疑 OP 想要一个统一的分布,分为两个值 0 和 1,这是你可以从 [0, 1] 上的 int 分布中得到的全部。
【解决方案3】:
std::uniform_real_distribution<double> dist{0.0, std::nextafter(1.0, 2.0)};

std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()}; 
std::mt19937 eng(seed);
double v = dist(eng); // a random double in the range 0.0 to 1.0 inclusive

尽管应该注意,浮点分布通常在舍入和最低有效位方面并不完美。

【讨论】:

  • 看起来uniform_real_distribution(a,b)是在[a,b)上定义的。 nextafter 是如何工作的?
  • @altroware: nextafter 在第二个参数的方向上给出第一个参数之后的下一个可表示值。因此,在这种情况下,它给出大于一的最小double。假设在实现生成器时对浮点问题进行了适当的关注(不是我会依赖的假设),这会导致它可能返回 [0, 1] 中的值,包括在内,而不是更多。
  • @EricPostpischil 确实:似乎在实践中uniform_real_distribution 实际上已经产生了一个包含范围。
  • @EricPostpischil 实际上它只是我正在查看的实现中的舍入问题,因此浮点问题可能是一个问题。然而,对于这些特定数字,四舍五入在我查看的实现中可以正常工作,并且确实会产生恰好在 [0,1] 范围内的值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-04
  • 2015-01-01
  • 2013-07-22
  • 2016-10-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多