函数返回范围 (a,b) 内呈指数分布的随机双精度值
Function returning random double with exponential distribution in range (a,b)
我想生成一个从 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
和 [=12 之间=].有人可以帮忙吗?提前致谢!
指数分布不限于正数,因此值可以从 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 这种情况)==1。
也不清楚为什么 (1/-.9) 因素??
我在第一个答案中误解了你的问题:)你已经在使用反演采样了。
要将一个范围映射到另一个范围,是一种典型的数学方法:
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
(这是线性缩放,所以分布会被保留)
(你可以验证:如果你为x
输入min
,结果是a
,如果你为x
输入max
, 你会得到 b
.)
现在的问题:指数分布的最大值为 inf
。所以,你不能使用这个等式,因为它总是 whatever / inf + 0
- 所以 0
。 (这在数学上是有道理的,但不符合您的需要)
因此,唯一正确的答案是: 两个固定数字之间不可能存在指数分布,因为您无法映射 [0,inf] -> [a,b]
因此你需要某种权衡,使你的结果尽可能指数。
出于好奇,我绞尽脑汁想了想各种可能性,但我发现你在这方面连数学都不如:P
不过,我用 Excel 和 140 万条随机记录做了一些测试:
我选择了一个随机数作为 "limit" (10) 并将计算结果四舍五入到小数点后一位。 (0, 0.1, 0.2 and so on) 这个数字我用来做最大为10的线性变换,ingoring任何大于1的结果。
在 140 万次计算中(生成 10-20 次),仅生成了 7-10 个大于 1 的随机数:
(概率密度函数,映射值后:第 100 列:= 1,第 0 列:= 0)
所以:
- 将值映射到
[0,1]
,使用上述线性方法,假设转换的最大值为 10。
如果你在转换后遇到一个>1的值——就再抽一个随机数,直到该值<1。
在 140 万次测试中只有 7-10 次出现,这应该足够接近了,因为重新绘制的数字将再次是 伪指数分布.
- 如果你想建造一艘宇宙飞船,其中导航取决于 0 和 1 之间的完美指数分布的数字 - 不要这样做,否则你应该是好的。
- (如果你想作弊:如果你遇到一个大于 1 的数字,只需从它的期望值中找到具有最大方差(即 Max(occurrences < expected occurrences))的记录 - 然后假设该值:P)
由于对指数分布的支持是从 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 观察值的测试集,将结果加载到我最喜欢的统计包中,结果符合预期。
我想生成一个从 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
和 [=12 之间=].有人可以帮忙吗?提前致谢!
指数分布不限于正数,因此值可以从 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 这种情况)==1。 也不清楚为什么 (1/-.9) 因素??
我在第一个答案中误解了你的问题:)你已经在使用反演采样了。
要将一个范围映射到另一个范围,是一种典型的数学方法:
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
(这是线性缩放,所以分布会被保留)
(你可以验证:如果你为x
输入min
,结果是a
,如果你为x
输入max
, 你会得到 b
.)
现在的问题:指数分布的最大值为 inf
。所以,你不能使用这个等式,因为它总是 whatever / inf + 0
- 所以 0
。 (这在数学上是有道理的,但不符合您的需要)
因此,唯一正确的答案是: 两个固定数字之间不可能存在指数分布,因为您无法映射 [0,inf] -> [a,b]
因此你需要某种权衡,使你的结果尽可能指数。
出于好奇,我绞尽脑汁想了想各种可能性,但我发现你在这方面连数学都不如:P
不过,我用 Excel 和 140 万条随机记录做了一些测试: 我选择了一个随机数作为 "limit" (10) 并将计算结果四舍五入到小数点后一位。 (0, 0.1, 0.2 and so on) 这个数字我用来做最大为10的线性变换,ingoring任何大于1的结果。
在 140 万次计算中(生成 10-20 次),仅生成了 7-10 个大于 1 的随机数:
(概率密度函数,映射值后:第 100 列:= 1,第 0 列:= 0)
所以:
- 将值映射到
[0,1]
,使用上述线性方法,假设转换的最大值为 10。 如果你在转换后遇到一个>1的值——就再抽一个随机数,直到该值<1。
在 140 万次测试中只有 7-10 次出现,这应该足够接近了,因为重新绘制的数字将再次是 伪指数分布.
- 如果你想建造一艘宇宙飞船,其中导航取决于 0 和 1 之间的完美指数分布的数字 - 不要这样做,否则你应该是好的。
- (如果你想作弊:如果你遇到一个大于 1 的数字,只需从它的期望值中找到具有最大方差(即 Max(occurrences < expected occurrences))的记录 - 然后假设该值:P)
由于对指数分布的支持是从 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 观察值的测试集,将结果加载到我最喜欢的统计包中,结果符合预期。