【问题标题】:Generate random double number in range [0, 1] in C在C中生成[0, 1]范围内的随机双数
【发布时间】:2020-05-26 10:54:58
【问题描述】:

我必须生成介于 0 和 1 之间的随机双精度数。如何使用 C 来做到这一点?我尝试生成一个介于 0 到 100 万之间的整数,然后将结果除以 1M,但效果不佳。

【问题讨论】:

  • 你能显示你试过的代码吗?
  • 随机性如何?你知道1*10^-100 (0.000...0001) 和2*10^-100 (0.000...0002) 之间有 2^52 个数字吗?你想生成这些数字中的任何一个吗? 大约,给予或接受一点
  • 也许(double)rand()/RAND_MAX 但这取决于所需的粒度,以及它们是否必须是唯一的等。
  • 均匀分布在 [1, 2[ -- ideone.com/SY5a04 -- 注意减去 1 不会得到均匀分布在 [0, 1[

标签: c random


【解决方案1】:

在 0 和 1 之间生成随机双精度数

需要考虑的一些事项:

包括 1.0??

我希望目标是“在 [0, 1) 范围内”,而不是“在 [0, 1] 范围内”。包含 1.0 会造成复杂性,因为它会使分布失衡。让我们假设 [0, 1)。

rand()质量

rand() 具有未指定的质量,其范围 [0...RAND_MAX] 可能不会以小于 2 的幂的 1 结尾。让我们假设 rand() 现在已经足够好了,RAND_MAX 是一个 Mersenne Number(这很常见),以便通过一个简单的 ^ 加入多个 rand() 呼叫。

小数字

大约一半的正面double 小于 1.0。他们都应该有机会吗?

典型值 DBL_MANT_DIG 是 53,所以:

在 [0.5...1.0) 范围内有 252double 值。
在 [0.25...0.5) 范围内有 252double 值。
在 [0.125...0.25) 范围内有 252double 值。
...

我们是否希望有 50% 的机会来自第一组,25% 来自下一组,12.5% 来自下一组......?

或满意:

表格253double值在[0.0...1.0)范围内均匀分布?


现在让我们实现第二个目标 - 更容易编码。

在 [0...253) 范围内生成一个整数 double,然后除以 253

RAND_MAX >= 0x7FFF 根据定义,所以我们得到至少 15 位的随机位。

下面是一些说明性代码,它们形成double [0.0 ... 1.0),效率不高。

// Illustrative code
double rand_double_01(void) {
  unsigned long long r = 0;
  #define RANDOM_BITS 15
  for (int i = 0; i < DBL_MANT_DIG; i += RANDOM_BITS) {
    r <<= RANDOM_BITS;
    r ^= rand();
  }
  r %= 1uLL << DBL_MANT_DIG;   // Mask off lower 53 bits
  double dr = r; // expected conversion is exact
  // scale [0 ... 1.0)
  dr /= 1uLL << DBL_MANT_DIG;  // expected conversion/quotient exact 
  return double dr; 
}

注意:当DBL_MANT_DIG &gt;= 64(不常见)或FLT_RADIX != 2(非常不常见)时,上述代码可能会失败。

【讨论】:

  • “不平衡分布”是什么意思?
  • @martinkunev 生成介于 0 和 1 之间的随机双精度数的目标包括在 [0...0.25)、[0. .25...0.5)、[0.5...0.75)、[0.75...1.0)。这占 [0.0...1.0)。如果我们需要潜在地形成 1.0,如在 [0.0...1.0] 中,我们是否将该 1.0 包含在这 4 个子组之一中,还是制作一个特殊的第 5 个?包括 1.0 会使分布不平衡。有一些方法可以弥补,但它们会降低效率。
【解决方案2】:

除法时要小心:当两个数字都是整数时,将使用整数除法(在这种情况下总是导致零)。

为了得到双精度,您需要强制除法为双精度除法,您可以通过将其中一个数字类型转换为双精度来实现:

a/b => integer division (when b is larger than a you end up with zero)

((double)a/b) => floating point division (this is what you are looking for)

【讨论】:

    猜你喜欢
    • 2010-10-20
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 2011-10-20
    • 1970-01-01
    • 1970-01-01
    • 2020-02-12
    • 1970-01-01
    相关资源
    最近更新 更多