在Python中为Random.random()组装浮点数

时间:2012-12-24 16:03:58

标签: python random floating-point floating-point-precision

我正在尝试从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]中没有减法吗?

1 个答案:

答案 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)函数使用xuniform上生成均匀分布的浮点数。

getrandbits