int 取值范围_一定范围内的随机数

老司机的新问题,取得[min, max]范围的随机数。

C版本的rand函数很不容易用对,直接用rand() % (max - min + 1) + min,这个公式不对。这个公式与取最低位的算法相同,而随机数的最低几位不一定等概率。

Donald Knuth博士教导我们正确的用法是 rand() / ((RAND_MAX + 1U) / (max - min + 1)) + min,这把rand的所有可能的值分成max - min个桶,每个数落入0号到max - 1号桶的概率相等。

C++中有std::uniform_int_distribution<>,可以直接取一定范围正态分布的随机数,我也没有深究过上面那个公式是否不正确。

结果还真的不正确。

因为大多数情况下,RAND_MAX / (max - min + 1) 都除不尽, 小数部分被舍去后,数值偏小。比如[RAND_MAX / 2, RAND_MAX / 2 + 1]这组,如果 RAND_MAX = 11,那么[0 - 4]的rand()被认为是5,概率是5/11,而5-11被认为是6,概率是6/11。

当采样次数与RAND_MAX同数量级时,这个概率差就显示出来了。这个值有时可能只有32767。大部分平台上这个值 为INT_MAX。

做个游戏什么的,还没有问题,一但用于统计数据,这就出错了。

stackoverflow上有人给出了正确的算法,注意这个算法是[0, max]的区间。

https://stackoverflow.com/questions/2509679/how-to-generate-a-random-integer-number-from-within-a-range#6852396​stackoverflow.com

本质上很简单,就是把RAND_MAX除不尽的部分从rand中消去。

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;
}

当RAND_MAX不够大时怎么办,可以通过以下公式扩展随机数。

unsigned long newrand  = rand() * ((unsigned long)RAND_MAX +1) + rand() 

注意RAND_MAX的取值,不要溢出了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值