您的实现很好:假设它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
range 中大约有不同的 IEEE 754 binary64 浮点数[0.0, 1.0)
,并且您的实现只能生成2^52
不同的输出,因此上述任何一种实现都不能生成大多数浮点数。更好的实现可以生成范围内的random()
每个浮点数,其概率等于该轮的子区间的长度到某种形式的最近舍入。然而,这样的实现会更加复杂(尽管实现起来并不特别困难),并且很少有应用程序会从更大的输出集中受益。正如 Python 之禅所说:“实用胜于纯洁。”x
[0.0, 1.0]
[0.0, 1.0)
x
编辑:为了说明上面的最后一段,这里有一些代码。该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