优化从随机数生成中更改整数范围

计算科学 优化 随机数生成
2021-12-22 12:11:20

我正在寻找将整数从随机数生成器更改为不同的包含数范围的最有效方法。

到目前为止,我知道两种方法:

  1. 将数字更改为 [0,1) 范围内的小数,并将其乘以新范围内的最小值和最大值*之间的差。
  2. 找到数字的余数除以新范围内的最小和最大数字*之间的差。

*差异必须增加 1 才能获得正确的结果包含范围


但是,这两种方法都有一个问题:

  1. 十进制方法涉及大量浮点计算,速度较慢
  2. 余数方法将有利于数字范围内的较低数字

为了说明上面的#2,考虑获取一个无符号字节的随机值。

您会得到一个 0-255 范围内的随机数。

假设您想要一个 1-255 范围内的数字,您可以使用以下公式:

number = random() % 255 + 1;

0-254 之间的任何数字都将简单地增加 1,从而为您提供 1-255 的范围。

255,但是也会给你一个 1,给 1 DOUBLE 的概率作为其余数字。

这说明了以下情况:

[newMin, newMin + oldMax % (newMax - newMin) ] 范围内数字的概率是 (oldMax - oldMin) / (newMax - newMin) 向上取整

范围内数字的概率 (newMin + oldMax % (newMax - newMin) , newMax] 为 (oldMax - oldMin) / (newMax - newMin) 向下舍入


在我的情况下,我得到一个 8 字节的值,因此在余数方法中这个缺陷的影响将需要一个非常大的数字样本,然后该缺陷会明显影响结果。

因此,如果这些是唯一可用的两种方法,我会忽略这个分布缺陷以提高性能。

有没有比方法#1 性能更好但结果比方法#2 更好的方法?

1个回答

获取范围内整数随机数的常用方法[0,,N)(半开范围)是一段代码形式

unsigned int rnd()
{
  unsigned int k;
  do {
    k = rand()
  } while (k >= RAND_MAX/N*N) 

  return k % N;
}

这是有效的,因为rand()在 range 中均匀地产生随机数[0,RAND_MAX]然后,do-while 循环[0,RAND_MAX/N*N)在上限为RAND_MAX小于或等于的最大倍数的范围内均匀地生成随机数RAND_MAX,因此k % N是范围内的均匀分布的随机数[0,N)

如果您想要区间中的随机数,请在区间[a,b)上使用上面的函数,[0,N=b-a)然后添加a到您获得的每个数字。