我正在尝试从python标准库中实现我自己的Random class版本。我可以生成随机位,我实现了getrandbits(n)函数。但是超类不使用此函数来计算random()返回的float。所以我必须自己实现:
def random(self):
exp = 0x3FF0000000000000
mant = self.getrandbits(52)
return struct.unpack("d", struct.pack("q", exp^mant))[0]-1.0
我使用0(正)的符号,1023的指数(2 ^ 0 = 1)和随机的mantisse。所以我从[1.0,2.0]得到一个数字。 random()函数必须返回[0.0,1.0]中的数字,所以我在返回之前减去1.0。 由于我不是浮点数的专家,我不确定这是以正确的方式完成的。不要通过减去精度而失去精确度吗?我可以从随机位构建数字,使其在[0.0,1.0]中没有减法吗?
答案 0 :(得分:2)
您的实现很好:假设getrandbits
本身足够随机,您的实现将以相同的概率为n / 2^52
生成0 <= n < 2^52
形式的每个数字,因此它是一个很好的近似值[0, 1)
上的统一分布。你使用的减法不是问题:减法的结果总是可以精确表示,因此减法中不会出现舍入或精度损失。
Python的random()
实现更多地按照return self.getrandbits(53) / 2**53.
的方式做了一些事情。效果是相似的,除了输出的分布现在是两倍之外:你得到每个数字{{1}对于具有相同概率的n / 2^53
。大多数应用程序不太可能在实践中注意到这两种实现之间的差异。如果你关心速度,那么这也可能更快,尽管你应该总是知道是否真的如此。
这些都不是完美的:0 <= n < 2^53
范围内有大约2^62
个不同的IEEE 754 binary64浮点数,并且您的实现只能生成[0.0, 1.0)
个不同的输出,因此大多数浮点数都是永远不会被上述任何一个实现生成。更好的2^52
实现可以在random()
范围内生成每个浮点数x
,其概率等于[0.0, 1.0]
的子区间长度为{{1}在某种形式的圆形到最近的情况下。然而,这样的实现将更加复杂(尽管不是特别难以实现),并且很少的应用程序将受益于更大的输出集。正如Python的禅宗所说:“实用性胜过纯洁。”
编辑:为了说明上面的最后一段,这里有一些代码。根据以上描述,[0.0, 1.0)
函数使用x
在uniform
上生成均匀分布的浮点数。
getrandbits