函数返回随机双精度,指数分布在范围(a,b)

时间:2015-11-06 20:50:57

标签: c# distribution exponential

我想生成从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之间,因此结果不会在ab之间。有人可以帮忙吗?提前谢谢!

3 个答案:

答案 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) enter image description here

所以:

  • 使用上面提到的线性方法将值映射到[0,1],假设转换最多为10。
  • 如果您遇到值>转换后的1 - 只需绘制另一个随机数,直到该值为< 1。

  • 在140万次测试中只有7-10次出现,这应该足够接近,因为重新绘制的数字将再次伪指数分布式

  • 如果你想建造一艘宇宙飞船,导航依赖于0到1之间完全指数分布的数字 - 不要这样做,否则你应该是好的。
  • (如果你想作弊:如果你遇到一个数字> 1,只需从它的预期值中找到具有最大方差的记录(即Max(出现次数<预期出现次数)) - 然后假设该值:P)

答案 1 :(得分:1)

由于对指数分布的支持为0到无穷大,无论速率如何,我都会假设您要求的指数被截断在a以下b以下。表达这一点的另一种方式是以X为条件的指数随机变量a <= 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观测值的测试集,将结果加载到我最喜欢的统计数据包中,结果如预期的那样。

答案 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)因子??