我想生成从a
到b
的随机数。问题是,数字必须以指数分布给出。
这是我的代码:
public double getDouble(double low, double high)
{
double r;
(..some stuff..)
r = rand.NextDouble();
if (r == 0) r += 0.00001;
return (1 / -0.9) * Math.Log(1 - r) * (high - low) + low;
}
问题是(1 / -0.9)* Math.Log(1 - r)不在0和1之间,因此结果不会在a
和b
之间。有人可以帮忙吗?提前谢谢!
答案 0 :(得分:3)
我在第一个答案中误解了你的问题:)你已经在使用反演采样了。
要将范围映射到另一个范围, 是一种典型的数学方法:
f(x) = (b-a)(x - min)/(max-min) + a
,其中
b = upper bound of target
a = lower bound of target
min = lower bound of source
max = upper bound of source
x = the value to map
(这是线性缩放,因此将保留分布)
(您可以验证:如果您为min
添加x
,则会生成a
,如果您为max
添加了x
,则得到b
。)
现在的问题:指数分布的最大值为inf
。所以,你不能使用这个等式,因为它总是whatever / inf + 0
- 所以0
。 (这在数学上是有道理的,但是并不适合你的需要)
所以,唯一正确的答案是: 两个固定数字之间没有指数分布,因为你无法映射[0,inf] - > [A,B] 强>
因此,您需要进行某种权衡,以使结果尽可能指数。
出于好奇,我围绕着不同的可能性包围了我,我发现你简单无法击败数学:P
但是,我用Excel和140万随机记录进行了一些测试: 我选择一个随机数作为“限制”(10)并将计算结果四舍五入到小数点后1位。 (0,0.1,0.2等)这个数字我用来执行线性变换,最大值为10,任何结果都大于1。
在140万次计算中(生成10-20次),只生成了大于1的7-10个随机数:
(概率密度函数,映射值后:列100:= 1,第0列:= 0)
所以:
[0,1]
,假设转换最多为10。如果您遇到值>转换后的1 - 只需绘制另一个随机数,直到该值为< 1。
在140万次测试中只有7-10次出现,这应该足够接近,因为重新绘制的数字将再次伪指数分布式。
答案 1 :(得分:1)
由于对指数分布的支持为0到无穷大,无论速率如何,我都会假设您要求的指数被截断在a
以下b
以下。表达这一点的另一种方式是以X
为条件的指数随机变量a <= X <= b
。
您可以通过计算截断分布的累积分布函数(CDF)作为指数密度的a
到x
的积分来推导出这种反演算法。将结果按a
和b
之间的区域进行缩放(F(b) - F(a)
,其中F(x)
是原始指数分布的CDF),使其成为带有区域的有效分布1.将派生的CDF设置为U
,一个统一的(0,1)随机数,并求解X
以获得反转。
我不编写C#,但这是用Ruby表示的结果。它应该非常透明地翻译。
def exp_in_range(a, b, rate = 1.0)
exp_rate_a = Math.exp(-rate * a)
return -Math.log(exp_rate_a - rand * (exp_rate_a - Math.exp(-rate * b))) / rate
end
我将默认速率设置为1.0,因为您没有指定,但显然您可以覆盖它。 rand
是Ruby的内置统一生成器。我认为其余的都是不言自明的。我为各种(a,b)值设置了几个100k观测值的测试集,将结果加载到我最喜欢的统计数据包中,结果如预期的那样。
答案 2 :(得分:0)
指数分布不限于正面,因此值可以从0到inf。将[0,infinity]缩放到某个有限区间的方法有很多,但结果不是指数分布的。 如果你只想要一个a和b之间的指数分布切片,你可以简单地从[ra rb]中绘制r,使得-log(1-ra)= a和-log(1-rb)= b,i,e ,
r=rand.NextDouble(); // assume this is between 0 and 1
ra=Math.Exp(-a)-1;
rb=Math.Exp(-b)-1;
rbound=ra+(rb-ra)*r;
return -Math.Log(1 - rbound);
为什么检查r == 0?我想你想要检查日志的参数是否> 0,所以检查r(或rbound int this case)== 1。 也不清楚为什么(1 / - .9)因子??