python - 在 Python 中为 Random.random() 组装 float

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

我正在尝试实现我自己的 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/

相关文章:

c++ - 如何在不丢失精度的情况下将 float 转换为 double(均以 IEEE-754 表示形式存储)?

c# - 从十进制转换为 float

ruby - 如何用尾随零舍入一个非常小的 float ?

python - Selenium 留下正在运行的进程?

java - Java随机打乱列表

c# - 随机化列表,同时确保重复项不连续

java - 从文本文件中选择一个随机单词

python - matplotlib.补丁 : One patch with mulitple colors

python - 如何使用python检查couchdb文档是否存在

python - 在执行函数时进入 python 解释器