【问题标题】:What is wrong in my attempt to generate a random number by Box-Muller?我尝试通过 Box-Muller 生成随机数有什么问题?
【发布时间】:2019-04-03 23:44:17
【问题描述】:

我正在尝试使用 Box-Muller 方法从高斯分布中生成一个随机数。然而,我的结果与事实相去甚远。

你能告诉我我做错了什么吗?

.stat.GetOneGaussianByBoxMuller:{ 
sq:{
    a:2.0*rand[abs[system"S"]]%abs[system"S"]-1;
    b:2.0*rand[abs[system"S"]]%abs[system"S"]-1;
    sq:(a*a)+(b*b);
    x:sq
   }/[{x>=1};1]; 

  :(2.0*rand[abs[system"S"]]%abs[system"S"]-1)*sqrt[(neg[2]*log[sq])%sq]
 };

【问题讨论】:

  • 您的问题解决了吗?

标签: random kdb


【解决方案1】:

你的回答有3个问题:q中操作的优先级、[-1;1]中如何生成随机变量、变量sq上的条件。

操作的优先级:

在下面提醒一下,a1a2 是不同的:

u:rand[1f];
a1:-1+2.0*u;
a2:2.0*u-1;

u:0.5
a1:0f
a2:-1f

u:0
a1:-1f
a2:-2f

在[-1;1]中生成一个随机变量:

使用以下内容:

a:-1+2.0*rand[1.0];
b:-1+2.0*rand[1.0];

sq 上的条件:

您确实考虑了sq >= 1 条件,但如果sq = 0 也有问题,因为您必须在最后一步除以sq

此外,在您的实现中,您计算​​了两次 a,其中 1) 不是最优的,2) 与方法不一致,因为在最后一次计算 sq 时必须使用相同的 a步骤,后者屈服于非常大的数字。我从wikipedia page 中获得了一些灵感,他们建议在不满足上述条件的情况下重新生成sq。因此在下面的实现中函数中的递归调用:

.stat.GetOneGaussianByBoxMuller:{ 
    a:-1+2.0*rand[1.0];
    b:-1+2.0*rand[1.0];
    sq:(a*a)+(b*b);
    if[(sq>=1)|(sq=0);
        :.stat.GetOneGaussianByBoxMuller[];
    ];
    :a*sqrt[(neg[2]*log[sq])%sq];
 };

您现在可以查看通过绘制以下数据集的直方图生成的数据:

([]val:{:.stat.GetOneGaussianByBoxMuller[]} each til 100000)

编辑:

您实际上可以通过为每个函数调用生成 2 个随机数来实现更高效的实现,如下所示:

.stat.GetOneGaussianByBoxMuller:{ 
    a:-1+2.0*rand[1.0];
    b:-1+2.0*rand[1.0];
    sq:(a*a)+(b*b);
    if[(sq>=1)|(sq=0);
        :.stat.GetOneGaussianByBoxMuller[];
    ];
    :(a*sqrt[(neg[2]*log[sq])%sq];b*sqrt[(neg[2]*log[sq])%sq]);
 };

([]val:raze {.stat.GetOneGaussianByBoxMuller[]} each til 50000)

这个实现需要 150 毫秒来生成 100000 个正态分布的随机数,而上面的实现需要 245 毫秒。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-04
    • 1970-01-01
    • 2016-02-16
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多