获取越来越不可能的随机数[关闭]
Posted
技术标签:
【中文标题】获取越来越不可能的随机数[关闭]【英文标题】:Get random number with larger numbers increasingly unlikely [closed] 【发布时间】:2014-08-26 03:27:22 【问题描述】:如何获得 k 到 h 范围内的随机数,使得数字越接近 h 越不可能出现?
我需要一个介于 20 到 1980 之间的数字。
【问题讨论】:
使用称为数学的魔法。找出你想要的分布方程。 可能重复的***.com/questions/5271598/… 知道如何在《卡坦岛定居者》中很少得到高低数字吗?这是因为你有两个骰子,并添加它们的值。去图吧。 @Fede 在那个问题的结果分布是均匀的。 @SteveP。我在想 MAX*abs([RAND+RAND] - 1) 中的一些东西 【参考方案1】:我在 Eclipse 中尝试了一些东西,结果如下。
interface Generator
double generate(double low, double high);
abstract class AbstractGenerator implements Generator
protected final Random rand;
public AbstractGenerator()
rand = new Random();
public AbstractGenerator(long seed)
rand = new Random(seed);
现在各种生成器实现的结果:
我尝试生成 0 到 9 级的 100k 个数字,在这里它们显示为条形。
Catan 2(加两个骰子)
class Catan2 extends AbstractGenerator
@Override
public double generate(double low, double high)
return low + (high - low) * Math.abs(-1 + (rand.nextDouble() + rand.nextDouble()));
结果:
0 : *******************
1 : ******************
2 : ****************
3 : **************
4 : ************
5 : *********
6 : *******
7 : *****
8 : ***
9 : *
Catan 3(加三个骰子)
class Catan3 extends AbstractGenerator
@Override
public double generate(double low, double high)
return low + (high - low) * Math.abs(-1.5 + (rand.nextDouble() + rand.nextDouble() + rand.nextDouble())) / 1.5;
结果:
0 : ***********************
1 : *********************
2 : *******************
3 : ***************
4 : ***********
5 : *******
6 : *****
7 : ***
8 : *
9 : *
Catan 4(加四个骰子)
class Catan4 extends AbstractGenerator
@Override
public double generate(double low, double high)
return low + (high - low) * Math.abs(-2 + (rand.nextDouble() + rand.nextDouble() + rand.nextDouble() + rand.nextDouble())) / 2D;
结果:
0 : ***************************
1 : ************************
2 : ********************
3 : **************
4 : *********
5 : *****
6 : ***
7 : *
8 : *
9 : *
我认为“Catan 3”是其中最好的。
公式为:low+(high-low)*abs(-1.5+(RAND+RAND+RAND))/1.5
基本上,我得到一个“山”分布,然后我将其居中并取其绝对值。然后我将其规范为所需的值。
【讨论】:
【参考方案2】:还有另一种选择。有一些标准方法可以在高斯分布上生成随机数。设置一个平均值为 k 且标准差为 h/5 的高斯 RNG。拒绝任何低于 k 的数字(大约是生成数字的一半)并拒绝所有大于 h 的数字(5% 或更少)。
如果您想优化结果,您可以调整标准差。实际上这是一个带有截尾的半高斯 RNG,所以数字不是线性的;你会更接近 k 而不是 h。
ETA:感谢@MightyPork 的评论,这让我开始思考。高斯分布是对称的,因此无需丢弃任何小于 k 的原始值。只需将它们从 k 下方移动到 k 上方相同的距离即可:
if (raw < k)
raw <- k + (k - raw)
end if
高于 h 的值仍然需要被拒绝。
【讨论】:
你的意思是 Random.nextGaussian()?你是怎么做截断的 - 一个循环生成数字,直到一些数字落在范围内? @MightyPork:是的。生成一个数字,对其进行测试,并且仅在其在范围内时才将其传递。生成的数字中只有一半以上会失败。【参考方案3】:假设我们的范围是 [0,4],创建一个这样的数组:
[000001111222334]
现在使用标准的Random
对象从数组中绘制。通过这样做,我们已经从均匀分布的绘图转变为我们自己设计的分布。实际上,我们不想使用辅助数组。您可以执行以下操作来代替辅助数组:
从 [0,14] 绘制;将 [0,4] 映射到 0,将 [5,8] 映射到 1,将 [9,11] 映射到 2,将 [12,13] 映射到 3,将 [14] 映射到 4。
这实际上取决于您的发行版是什么样的。您可以通过从不同范围内的均匀分布多次绘制来近似从非均匀分布绘制。当然,如果你知道分布的概率质量函数或概率密度函数,那么你就是金子。
【讨论】:
我需要一个介于 20 到 1980 之间的数字,使用您的方法会创建一个非常大的数组。 @RedHatter,将其添加到您的问题中。 @RedHatter 我认为我的第二次编辑对你的帮助最大。【参考方案4】:如果您需要很好地控制数字的分布,那么一个很好的方法是求逆法。创建一个 (x,y) 对的排序表,其中 x 和 y 都单调增加:x 从 0 到 1,y 从您需要的伪随机数的低值到高值。算法是:
x = uniform random float in [0..1)
Search the table to find (x[i],y[i]) such that x[i] <= x < x[i+1]
// Return linearly interpolated y value
return y[i] + (x - x[i]) / (x[i+1] - x[i]) * (y[i+1] - y[i])
您可以通过表格条目控制返回值的分布。
如果表只包含(0,0)和(1,1),那么显然返回值等于x,分布是均匀的。要获得更高的数字,请描述一条在开始时增长更快且在 x 值越高越平坦的曲线,例如:
(0,0) (0.25,0.5) (1,1)
您应该能够明白为什么会这样。在均匀分布中,一半的数字介于 0 和 0.5 之间。使用此表,只有四分之一的数字在该范围内,因此其他四分之三的数字在 0.5 到 1 之间。根据您的需要,高数字更频繁。
您可以创建任意形状的平滑曲线,只要它是单调递增的。如果表的对数多于几对,请考虑二分查找以提高速度。
对于 20 到 1980 的范围,对应的表格如下:
(0, 20) (0.25, 1000) (1, 1980)
如果你需要整数,你会想要使用
(0, 20) (0.25, 1000) (1, 1981)
然后从结果中截断分数。
同样,您可能希望在表格中添加更多点以使 ICDF 更平滑。这是为了说明。
数学
存储在表中的曲线称为返回的伪随机数的逆累积密度函数 (ICDF)。概率分布函数 (PDF) 是曲线下面积为 1 的非负函数。常用的 PFD 有均匀、指数和正态。对应的 CDF 是 PDF 的运行积分。 ICDF 是 CDF 的倒数。众所周知,要使用任何给定的 PDF 生成随机数,您可以找到 ICDF 并应用上述算法。
【讨论】:
以上是关于获取越来越不可能的随机数[关闭]的主要内容,如果未能解决你的问题,请参考以下文章