函数返回范围 (a,b) 内呈指数分布的随机双精度值

Function returning random double with exponential distribution in range (a,b)

我想生成一个从 ab 的随机数。问题是,这个数字必须服从指数分布。

这是我的代码:

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 的指数].另一种表达方式是指数随机变量 Xa <= X <= b.

为条件

您可以通过计算截断分布的累积分布函数 (CDF) 作为指数密度从 ax 的积分来推导出反演算法。按 ab 之间的面积缩放结果(即 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 观察值的测试集,将结果加载到我最喜欢的统计包中,结果符合预期。