我正在尝试实现我自己的 Random class 版本来自Python标准库。我可以生成随机位,并实现了 getrandbits(n) 函数。但父类(super class)不使用此函数来计算 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) 和随机尾数。所以我从 [1.0, 2.0) 中得到一个数字。 random() 函数必须返回 [0.0, 1.0) 中的数字,因此我在返回之前减去 1.0。 由于我不是 float 方面的专家,因此我不确定这样做是否正确。减法不会损失精度吗?我可以从随机位构建数字,使其处于 [0.0, 1.0) 范围内而不进行减法吗?
最佳答案
您的实现很好:假设 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 二进制 64 float 在 [0.0, 1.0)
范围内,并且您的实现只能生成 2^52
不同的输出,因此大多数 float 永远不能由上述任一实现生成。更好的random()
实现可以生成每个 float x
在 [0.0, 1.0]
范围内概率等于 [0.0, 1.0)
子区间的长度四舍五入为 x
在某种形式的舍入到最近的情况下。然而,这样的实现会更加复杂(尽管实现起来并不是特别困难),并且很少有应用程序会从更大的输出集中受益。正如 Python 禅宗所说:“实用性胜过纯粹性。”
编辑:为了说明上面的最后一段,这里有一些代码。 uniform
函数使用getrandbits
在 [0, 1]
上生成均匀分布的 float 根据上面的描述。
"""
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
关于python - 在 Python 中为 Random.random() 组装 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14023453/