【问题标题】:create a random number less than a max given value创建一个小于最大给定值的随机数
【发布时间】:2010-09-19 17:58:24
【问题描述】:

我想做的是创建一个函数,该函数接受一个参数,该参数是随机生成应该创建的数字的限制。我经历过一些生成器只是一遍又一遍地重复生成的数字。

如何制作一个不连续返回相同数字的生成器。有人可以帮助我实现我的目标吗?

int randomGen(int max)
{
  int n;      
  return n;
}

【问题讨论】:

标签: c random


【解决方案1】:

rand 获得均匀分布的结果的最简单方法是这样的:

int limited_rand(int limit)
{
  int r, d = RAND_MAX / limit;
  limit *= d;
  do { r = rand(); } while (r >= limit);
  return r / d;
}

结果将在0limit-1 的范围内,只要值0RAND_MAX 与原始rand 函数的概率相等,每个结果的发生概率都相等。

我使用的其他方法,例如模算术或不带循环的除法会引入偏差。通过浮点中间体的方法不能避免这个问题。从rand 获得好的随机浮点数至少同样困难。如果你想要随机浮点数,使用我的整数函数(或它的改进)是一个很好的起点。

编辑:这里解释一下我所说的偏见。假设 RAND_MAX 是 7,limit 是 5。假设(如果这是一个好的 rand 函数)输出 0、1、2、...、7 的可能性相同。取rand()%5 会将 0、1、2、3 和 4 映射到它们自己,但将 5、6 和 7 映射到 0、1 和 2。这意味着值 0、1 和 2 的可能性是其两倍弹出值 3 和 4。如果您尝试重新缩放和划分,则会发生类似的现象,例如使用 rand()*(double)limit/(RAND_MAX+1) 这里,0 和 1 映射到 0,2 和 3 映射到 1,4 映射到 2、5 和6 映射到 3,7 映射到 4。

RAND_MAX 的大小在一定程度上减轻了这些影响,但如果 limit 很大,它们可能会再次出现。顺便说一句,正如其他人所说,对于线性同余 PRNG(rand 的典型实现),低位往往表现得非常糟糕,所以当limit 是 2 的幂时使用模运算可以避免偏差问题我描述了(因为在这种情况下,limit 通常会平分 RAND_MAX+1),但你会遇到一个不同的问题。

【讨论】:

  • 当然,如果 limit > RAND_MAX,这将导致除以 0。(但是,如果您没有真正从您想要的范围内获得统一的随机数,这可能是件好事。 )
  • 是的..如果您担心这可能真的发生,您应该使用一个多次调用rand 的函数来包装rand 并附加这些位,直到您在一个大范围内获得均匀分布已知固定的二次幂范围。
【解决方案2】:

这个怎么样:

 int randomGen(int limit)
 {
    return rand() % limit;

 }
   /* ... */
 int main()
 {
    srand(time(NULL));
    printf("%d", randomGen(2041));

    return 0;
  }

【讨论】:

  • 这种常用方法是不正确的,并且会导致有偏差的随机数,除非limit 是 2 的幂。
  • 简单,并且OP没有提到每个数字的ab相等概率的需要。
  • 如果 rand 是一个线性同余生成器,即使 limit 是 2 的幂,它也会给出有偏差的结果。
  • 好吧,如果原来的 rand 有偏见,那么修复它就更难了……你最好自己写。
  • @R.:LCG 很糟糕,但对于非科学应用,它们的高位表现还不错。但不是他们的低阶。
【解决方案3】:

任何伪随机生成器都会在一段时间内一遍又一遍地重复这些值。 C只有rand(),如果你使用它,你应该用srand()明确地初始化随机种子。但可能你的平台比这更好。

在 POSIX 系统上,您应该在 man drand48 页面下找到一整套函数。他们有一个明确的时期和质量。您可能会在那里找到您需要的东西。

【讨论】:

    【解决方案4】:

    在不明确了解您平台的随机生成器的情况下,请勿执行rand() % max。简单随机数生成器的低位字节通常根本不是随机的。

    改为使用(返回包含 min 和 max non-inclusive 之间的数字):

    int randomIntegerInRange(int min, int max)
    {
        double tmp = (double)rand() / (RAND_MAX - 1.);
        return min + (int)floor(tmp * (max - min));
    }
    

    更新:上面的解决方案是有偏差的(参见 cmets 的解释),并且可能不会产生统一的结果。我不删除它,因为它是不该做的事的一个非自然示例。请使用本主题其他地方推荐的拒绝方法。

    【讨论】:

    • @Matt:这行得通。借助 rand() 的其他知识,我将使用 2 的幂和拒绝进行模数。但是在这里,如果 rand() 是一个线性同余废话,没有更好的方法。
    • 此解决方案无法解决偏差。
    • @R. rand() 实现在高阶项中存在偏差是非常困难的。模数存在问题,但这种方法没有问题。你在说什么偏见?
    • 如果max-min 没有均匀地进入RAND_MAX+1,一些输出将比其他输出有更多的输入映射到它们。
    • R 是正确的,存在 偏差。这是一个简单的鸽巢原理问题 - 如果您尝试将每个可能的 rand() 值映射到一个输出整数上,并且可能的输出数量不完全除以可能的 rand() 值的数量,那么将映射一些输出值来自比其他人更少的rand() 值。因此,偏见。
    猜你喜欢
    • 2020-05-10
    • 2011-12-04
    • 2014-12-27
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-16
    相关资源
    最近更新 更多