如何从范围内产生一个随机数 [英] How to generate a random number from within a range

查看:172
本文介绍了如何从范围内产生一个随机数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是从previously发布问题上遵循:

This is a follow on from a previously posted question:

如何在C生成随机数?

我希望能够从一个特定的范围内生成随机数,例如1至6个以模仿骰子的侧面

I wish to be able to generate a random number from within a particular range, such as 1 to 6 to mimic the sides of a dice.

我怎么会去这样做?

推荐答案

所有的答案到目前为止,在数学上是错误的。返回兰特()%N 不统一给在范围内的数 [0,N)除非 N 分为<其中code>兰特区间的长度()收益(即是2的功率)。此外,一个不知道是否模量兰特()是独立的:它可能是他们去 0,1,2,... ,这是统一的,但不是很随意。它似乎是合理的进行的唯一的假设是兰特()拿出泊松分布:同样大小的任意两个不重叠的子区间是等可能的和独立的。对于一组有限的值,这意味着一个均匀分布,也确保了兰特()的值被很好地散了。

All the answers so far are mathematically wrong. Returning rand() % N does not uniformly give a number in the range [0, N) unless N divides the length of the interval into which rand() returns (i.e. is a power of 2). Furthermore, one has no idea whether the moduli of rand() are independent: it's possible that they go 0, 1, 2, ..., which is uniform but not very random. The only assumption it seems reasonable to make is that rand() puts out a Poisson distribution: any two nonoverlapping subintervals of the same size are equally likely and independent. For a finite set of values, this implies a uniform distribution and also ensures that the values of rand() are nicely scattered.

这意味着,改变的兰特范围()是把它划分成箱的唯一正确途径;例如,如果 RAND_MAX == 11 和你想有一个范围 1..6 ,你应该分配 {0,1} 1 {2,3} 2,依此类推。这些是不相交的,相等大小的时间间隔,从而被均匀地和独立地分布

This means that the only correct way of changing the range of rand() is to divide it into boxes; for example, if RAND_MAX == 11 and you want a range of 1..6, you should assign {0,1} to 1, {2,3} to 2, and so on. These are disjoint, equally-sized intervals and thus are uniformly and independently distributed.

使用浮点除法的建议是合理的数学但是从原则上四舍五入问题受到影响。也许双击是足够高的precision,使其工作;也许不是。我不知道,我不希望有弄明白;在任何情况下,答案是取决于系统。

The suggestion to use floating-point division is mathematically plausible but suffers from rounding issues in principle. Perhaps double is high-enough precision to make it work; perhaps not. I don't know and I don't want to have to figure it out; in any case, the answer is system-dependent.

正确的方法是使用整数运算。也就是说,你想要的东西类似如下:

The correct way is to use integer arithmetic. That is, you want something like the following:

#include <stdlib.h> // For random(), RAND_MAX

// Assumes 0 <= max <= RAND_MAX
// Returns in the closed interval [0, max]
long random_at_most(long max) {
  unsigned long
    // max <= RAND_MAX < ULONG_MAX, so this is okay.
    num_bins = (unsigned long) max + 1,
    num_rand = (unsigned long) RAND_MAX + 1,
    bin_size = num_rand / num_bins,
    defect   = num_rand % num_bins;

  long x;
  do {
   x = random();
  }
  // This is carefully written not to overflow
  while (num_rand - defect <= (unsigned long)x);

  // Truncated division is intentional
  return x/bin_size;
}

环路是必要的以获得完全均匀的分布。例如,如果您将得到随机数从0到2,你想唯一的从0到1,你刚才一直拉,直到你没有得到一个2;不难检查这给0或1的概率相等。这种方法也被在于号给在他们的答案的链路描述的,虽然$ C $光盘不同。我使用随机(),而不是兰特(),因为它有一个更好的分配(由人指出页兰特())。

The loop is necessary to get a perfectly uniform distribution. For example, if you are given random numbers from 0 to 2 and you want only ones from 0 to 1, you just keep pulling until you don't get a 2; it's not hard to check that this gives 0 or 1 with equal probability. This method is also described in the link that nos gave in their answer, though coded differently. I'm using random() rather than rand() as it has a better distribution (as noted by the man page for rand()).

如果你想获得默认范围之外的随机值 [0,RAND_MAX] ,那么你必须做一些事情棘手。也许最有利的是定义一个函数 random_extended(),拉 N 位(使用 random_at_most()),并在返回 [0,2 ** N),然后申请 random_at_most() random_extended()在<$ C $的c>随机()(和 2 ** N - 1 代替 RAND_MAX )拉一个随机值小于 2 ** N ,假设你有一个数值类型,它可以容纳这样的值。最后,当然,你可以在获取值 [MIN,MAX] 使用分钟+ random_at_most(最大值 - 最小值)包括负值。

If you want to get random values outside the default range [0, RAND_MAX], then you have to do something tricky. Perhaps the most expedient is to define a function random_extended() that pulls n bits (using random_at_most()) and returns in [0, 2**n), and then apply random_at_most() with random_extended() in place of random() (and 2**n - 1 in place of RAND_MAX) to pull a random value less than 2**n, assuming you have a numerical type that can hold such a value. Finally, of course, you can get values in [min, max] using min + random_at_most(max - min), including negative values.

这篇关于如何从范围内产生一个随机数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆