【问题标题】:Generate uniform pseudo-random numbers in a closed interval在封闭区间内生成统一的伪随机数
【发布时间】:2018-09-25 14:20:40
【问题描述】:

在闭区间 [0,1] 而不是通常的 [0,1) 中生成伪随机数的最佳方法是什么?我想出的一个想法是拒绝(1/2,1)中的值,然后将数字加倍。不知道有没有更好的方法。

real x
do
   call random_number(x)
   if (x <= 0.5) exit
end do
x = 2*x
print *, x
end

最重要的要求是算法不应该做出比random_number()生成的分布更差的分布(在均匀性和相关性方面)。我也喜欢简单。 random_number() 的包装器会非常好,我不打算实现一个全新的生成器。


正如@francescalus 在 cmets 中指出的那样,使用上述算法,[0,1] 中的大量数字出现的概率为零。下面的代码实现了一种稍微不同的方法:将区间扩大一点,然后去掉超过 1 的值。它应该在这方面表现更好。

real x
do
   call random_number(x)
   x = x*(1 + 1e-6)
   if (x <= 1.) exit
end do
print *, x
end

【问题讨论】:

  • "Best" 太宽泛了,所以也许您可以解释一下您在这个新发行版中需要哪些属性。例如,在问题的情况下,区间 [0,1] 中的许多数字现在出现的概率为零。
  • @francescalus 最重要的要求是它不应该“破坏”random_number() 生成的分布。我不想实现一个全新的生成器,只是想把random_number() 包装进去。我希望它简洁。从第一个要求来看,如果我正确理解第一个算法的问题,我添加的第二个算法应该会更好。
  • @ArchStanton wiki 页面提到了根据 U(0,1) 生成的随机数,这并不意味着必须包含 1。我还认为该页面的限制有点混乱。如果您查看数字食谱,它会得到很好的解释。简而言之,您可以毫无问题地使用 random_number 进行 Box-Muller 变换。你会得到一个非常好的高斯分布。
  • 4个均匀分布U((0,1))、U([0,1))、U((0,1])和U([0,1)的累积分布函数]) 是相同的,所以你担心的东西实际上什么都不是。
  • @kvantour 包含 1 不会伤害(代价是在 [0,1) 中排除一些其他可表示的实数),但是任何明确使用的代码它的包含(例如,通过显式测试与 1 的相等性)可能是错误代码(恕我直言)。

标签: random fortran


【解决方案1】:

交换 x 和 1-x 怎么样?抱歉,我的 Fortran 生锈了

real function RNG()
real ::    x
logical, save :: swap = .TRUE.

call random_number(x)
if (swap .EQV. .TRUE.)
    RNG = x
    swap = .FALSE.
else
    RNG = 1.0 - x
    swap = .TRUE.
end if

end

如果你想使用 Box-Muller,在任何地方都使用 1-U,它应该可以工作

z0 = sqrt(-2.0*log(1.0-U1))*sin(TWOPI*U2)
z1 = sqrt(-2.0*log(1.0-U1))*cos(TWOPI*U2)

Box-Muller 的拒绝版本也是如此

【讨论】:

  • 这种做法只是将问题从半开区间[0,1)交换到半开区间(0,1]。OP请求闭区间[0,1]
  • @kvantour 不,有时采样为 0 时返回 0,有时采样为 0 时返回 1,因此此方法的总间隔为 [0...1]跨度>
  • 啊,是的,你是对的,但是数字 0 和 1 的采样概率是所有其他数字的一半,这会扭曲你的分箱(非常轻微)
  • @kvantour 是正确的,我们将一半的零换成一
  • @kvantour 谢谢,当标准说我们将有十几个 RNG 但它们都将在 [0...1) 区间内时,这是 C++ 中已知的事情。你是对的1.0D0-U1,我为我的 Fortran skllls 变形而道歉
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-08-07
  • 2013-03-31
  • 2011-09-18
  • 2018-03-20
  • 2011-02-08
  • 2015-04-08
  • 1970-01-01
相关资源
最近更新 更多