你的實現是好的:假設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 binary64浮動範圍[0.0, 1.0)
,而您的實現只能產生2^52
不同輸出,所以大部分這些彩車不能由上述任何一種實現的產生。更好的random()
實現可以產生範圍爲[0.0, 1.0]
的每個浮點數x
,其概率等於子週期的長度[0.0, 1.0)
,該概率在某種形式的舍入到最近的情況下舍入到x
。然而,這樣的實現將會複雜得多(儘管不是特別難以實現),並且很少的應用程序會從更大的輸出集中受益。正如Python的禪說:「實用性勝過純潔。」
編輯:爲了說明的最後一段之上,這裏的一些代碼。根據上面的描述,uniform
函數使用getrandbits
在[0, 1]
上生成均勻分佈的浮體。
"""
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
對不起,但這聽起來對我來說是一個非常糟糕的主意。問自己:「唐納德克努特會做什麼?」並對最終解決方案進行Diehard測試。 – duffymo
這實際上並不是關於隨機生成器。這可以認爲是正確的(因爲我正在圍繞現有的和經過測試的生成器封裝Python類)。問題是,如何根據隨機位的python標準庫來組裝浮點隨機數。 – qasfux