代码之家  ›  专栏  ›  技术社区  ›  Tim Pietzcker

Random.Randint(1,10)能返回11吗?

  •  10
  • Tim Pietzcker  · 技术社区  · 15 年前

    当研究 this question 读取源代码 random.py 我开始怀疑 randrange randint 真正表现得像“广告”。我很倾向于相信,但是我读到的方式, 兰德兰 基本上实现为

    start + int(random.random()*(stop-start))
    

    (假设整数值为 start stop 如此 randrange(1, 10) 应返回介于1和9之间的随机数。

    randint(start, stop) 正在呼叫 randrange(start, stop+1) ,从而返回一个介于1和10之间的数字。

    我现在的问题是:

    如果 random() 曾经回来过 1.0 然后 randint(1,10) 会回来 11 不是吗?

    3 回复  |  直到 10 年前
        1
  •  27
  •   aioobe    15 年前

    random.py 博士:

    """Get the next random number in the range [0.0, 1.0)."""
    

    这个 ) 指示间隔为 排他性 1。也就是说,它永远不会返回1.0。

    这是数学上的一个普遍规律, [ ] 是包容的,而 ( ) 是独占的,并且两种类型的括号可以混合为 (a, b] [a, b) . 看一看 wikipedia: Interval (mathematics) 正式解释。

        2
  •  12
  •   Mark Dickinson Alexandru    10 年前

    其他答案也指出 random() 总是 严格地 小于 1.0 然而,这只是故事的一半。

    如果你在计算 randrange(n) 作为 int(random() * n) 需要知道对于任何python float x 令人满意的 0.0 <= x < 1.0 ,以及任何正整数 n ,这是真的 0.0 <= x * n < n ,这样 int(x * n) 严格小于 n .

    这里有两件事可能出错:第一,当我们计算 x * n , n 被隐式转换为float。足够大的 n ,该转换可能会更改值。但是,如果您查看python源代码,您会发现它只使用 int(随机()*n) 方法 n 小于 2**53 (这里和下面我假设平台使用IEEE754双精度),这是转换 n 对于一个浮动,保证不会丢失信息(因为 n 可以精确地表示为浮点数)。

    第二件可能出错的事情是乘法的结果 x*n (现在是作为浮点数的乘积执行的,记住)可能不会完全表示,因此会涉及到一些舍入。如果 X 足够接近 可以想象,四舍五入将结果四舍五入到 n 本身。

    为了防止这种情况发生,我们只需要考虑 X ,即(在几乎所有运行python的计算机上) 1 - 2**-53 . 所以我们需要证明 (1 - 2**-53) * n < n 对于正整数 n 因为这永远都是真的 random() * n <= (1 - 2**-53) * n .

    证明 (草图)让 k 是唯一整数 K 这样 2**(k-1) < n <= 2**k . 然后下一个浮动从 n n - 2**(k-53) . 我们需要证明 n*(1-2**53) (即,产品的实际值、未经计算的值)更接近 N-2**(K-53) n 使其始终向下取整。但是一个小小的运算表明 n*(1-2**-53) n 2**-53 * n ,而距离 N*(1-2**- 53) N-2**(K-53) (2**k - n) * 2**-53 . 但是 2**k - n < n (因为我们选择了 K 以便 2**(k-1) < n )所以产品 更接近 N-2**(K-53) ,所以 四舍五入(假设平台正在执行某种形式的四舍五入操作)。

    所以我们很安全。唷!


    附录(2015-07-04):上述假设采用IEEE754二进制64算法,与偶数取整模式有关。在许多机器上,这种假设是相当安全的。然而,在使用x87 fpu进行浮点运算的x86机器上(例如32位Linux的各种风格),有可能 double rounding 在乘法中,这使得 random() * n 向上的 n 在这种情况下 随机化() 返回最大可能值。最小的这样 n 这可能发生的原因是 n = 2049 . 参见讨论 http://bugs.python.org/issue24546 更多。

        3
  •  3
  •   Jack    15 年前

    从python文档:

    几乎所有的模块函数都依赖于基本函数random(),它在半开范围内均匀地生成一个随机浮点[0.0,1.0]。

    就像几乎所有的浮点数一样……

    推荐文章