【问题标题】:Function returning random double with exponential distribution in range (a,b)函数返回具有指数分布在 (a,b) 范围内的随机双精度
【发布时间】:2016-02-08 02:43:57
【问题描述】:

我想生成一个从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 之间。有人可以帮忙吗?提前致谢!

【问题讨论】:

标签: c# distribution exponential


【解决方案1】:

指数分布不限于正数,因此值可以从 0 到 inf。有很多方法可以将 [0,infinity] 缩放到某个有限区间,但结果不会呈指数分布。 如果您只想要 a 和 b 之间的指数分布的一部分,您可以简单地从 [ra rb] 绘制 r 使得 -log(1-ra)=a 和 -log(1-rb)=b ,即,

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

【讨论】:

    【解决方案2】:

    我在第一个答案中误解了您的问题 :) 您已经在使用反演采样。

    要将一个范围映射到另一个范围,一种典型的数学方法:

    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。 (这在数学上是有道理的,但 ofc 不符合您的需求)

    所以,唯一正确的答案是:两个固定数字之间不可能有指数分布,因为你不能映射 [0,inf] -> [a,b]

    因此,您需要进行某种权衡,以使您的结果尽可能指数

    出于好奇,我盘算着不同的可能性,我发现在这方面你根本无法击败数学:P

    但是,我使用 Excel 和 140 万条随机记录进行了一些测试: 我选择了一个随机数作为“限制”(10)并将计算结果四舍五入到小数点后 1 位。 (0, 0.1, 0.2 等等) 这个数字我用来执行线性变换,最大值为 10,输入任何大于 1 的结果。

    在 140 万次计算中(生成了 10-20 次),仅生成了 7-10 个大于 1 的随机数:

    (概率密度函数,映射值后:第 100 列:= 1,第 0 列:= 0)

    所以:

    • 使用上述线性方法将值映射到[0,1],假设转换的最大值为 10。
    • 如果你在变换后遇到值>1——就再画一个随机数,直到值

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

    • 如果您想建造一艘宇宙飞船,其导航取决于 0 到 1 之间的完美指数分布的数字 - 不要这样做,否则您应该做得很好。
    • (如果你想作弊:如果你遇到一个大于 1 的数字,只需从它的预期值中找到具有最大差异(即 Max(occurrences

    【讨论】:

    • 谢谢,这让我很清楚这个问题:)
    【解决方案3】:

    由于对指数分布的支持是 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 观测值的测试集,将结果加载到我最喜欢的 stats 包中,结果符合预期。

    【讨论】:

    • // 具有范围的指数分布 C# double ExpInRange(Random R, double A, double B, double Rate = 1.0) { double ERA = Math.Exp(-Rate * A);返回 -Math.Log(ERA - R.NextDouble() * (ERA - Math.Exp(-Rate * B))) / 比率; }
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多