你的实现是好的:假设getrandbits
本身就足以随机的,您的实现将产生形式n/2^52
的每个数字为0 <= n < 2^52
以相等的概率,所以这是一个很好的近似上[0, 1)
均匀分布。你使用的减法不是一个问题:减法的结果总是可以精确表示的,所以在减法中没有舍入或精度损失。
Python的random()
实现不沿return self.getrandbits(53)/2**53.
线的影响是类似的东西多,但产出的分布是现在的两倍罚款:你得到的形式n/2^53
的每个数0 <= n < 2^53
概率相同。大多数应用程序在实践中不太可能会注意到这两种实现之间的差异。如果你关心速度,这很可能也会更快,尽管你总是应该知道这是否是事实。
这些都不是完美的:有大约2^62
的IEEE 754 binary64浮动范围[0.0, 1.0)
,而您的实现只能产生2^52
不同输出,所以大部分这些彩车不能由上述任何一种实现的产生。更好的random()
实现可以产生范围为[0.0, 1.0]
的每个浮点数x
,其概率等于子周期的长度[0.0, 1.0)
,该概率在某种形式的舍入到最近的情况下舍入到x
。然而,这样的实现将会复杂得多(尽管不是特别难以实现),并且很少的应用程序会从更大的输出集中受益。正如Python的禅说:“实用性胜过纯洁。”
编辑:为了说明的最后一段之上,这里的一些代码。根据上面的描述,uniform
函数使用getrandbits
在[0, 1]
上生成均匀分布的浮体。
"""
High quality uniform random variable on [0, 1].
Simulates round(X) where X is a real random variable uniformly distributed on
the interval [0, 1] and round is the usual round-to-nearest rounding function
from real numbers to floating-point.
"""
from __future__ import division
import random
precision = 53
emin = -1021
def random_significand():
return (random.getrandbits(precision) + 1) // 2/(2**precision)
def uniform():
for i in xrange(1 - emin):
if random.getrandbits(1):
return (random_significand() + 0.5)/2**i
# Subnormal
return random_significand()/2**i
对不起,但这听起来对我来说是一个非常糟糕的主意。问自己:“唐纳德克努特会做什么?”并对最终解决方案进行Diehard测试。 – duffymo
这实际上并不是关于随机生成器。这可以认为是正确的(因为我正在围绕现有的和经过测试的生成器封装Python类)。问题是,如何根据随机位的python标准库来组装浮点随机数。 – qasfux