web-dev-qa-db-ja.com

random.uniform(0,1)は0または1を生成できますか?

ドキュメント では、uniform(0,1)が_0_および_1_の値を生成できる可能性があると言われています。

uniform(0, 1)を10000回実行しましたが、ゼロは生成されませんでした。 uniform(0, 0.001)の場合でも同様です。

random.uniform(0,1)は_0_または_1_を生成できますか?

9
Venkatesh Gandi

uniform(0, 1)は_0_を生成できますが、neverは_1_を生成します。

documentation は、エンドポイントbcouldが生成された値に含まれることを示しています。

エンドポイント値bは、式a + (b-a) * random()の浮動小数点の丸めに応じて、範囲に含まれる場合と含まれない場合があります。

したがって、uniform(0, 1)の場合、0 + (1-0) * random()に簡略化された式1 * random()は、_1_を正確に生成できる必要があります。これは、random.random()が1.0 _exactly. However,_ random()_*never* produces_ 1.0`の場合にのみ発生します。

random.random()ドキュメント を引用:

[0.0、1.0)の範囲の次のランダムな浮動小数点数を返します。

表記_[..., ...)_は、最初の値がすべての可能な値の一部であることを意味しますが、2番目の値はそうではありません。 random.random()は最大でも非常に近いから_1.0_までの値を生成します。 Pythonのfloatタイプは IEEE 754 base64浮動小数点値 であり、これは2進分数(1/2、1/4、1/5など)の数をエンコードします。値を構成し、random.random()が生成する値は、_2 ** -1_(1/2)から_2 ** -53_(1/9007199254740992)までの53の小数のランダムな選択の合計です)。

ただし、これは_1.0_に非常に近い値を生成する可能性があるため、浮動小数点ナブマーを乗算するときに発生する丸めエラーとともに、cansome値に対してbを生成しますaおよびbのただし、_0_および_1_はこれらの値には含まれません。

random.random()canは0.0を生成するため、aは常にrandom.uniform()a + (b - a) * 0 == a)の可能な値に含まれることに注意してください。 random.random()が生成できる_2 ** 53_異なる値(53の2進数のすべての可能な組み合わせ)があるため、その可能性は_2 ** 53_に1つ(つまり、9007199254740992に1つ)ですこれまでに起こった。

したがって、random.random()が生成できる最大の値は1 - (2 ** -53)です。 _b - a_に十分に小さい値を選択するだけで、より大きなrandom.random()値を掛けたときに丸めが有効になります。 _b - a_が小さいほど、その可能性が高くなります。

_>>> import random, sys
>>> def find_b():
...     a, b = 0, sys.float_info.epsilon
...     while random.uniform(a, b) != b:
...         b /= 2
...     else:
...         return b
...
>>> print("uniform(0, {0}) == {0}".format(find_b()))
...
uniform(0, 4e-323) == 4e-323
_

_b = 0.0_を押すと、1023回除算されます。上記の値は、1019回の除算でラッキーになったことを意味します。これまでに見つけた最高の値(上記の関数をmax()でループで実行)は_8.095e-320_(1008目盛)ですが、おそらくそれより高い値があります。それはすべて偶然のゲームです。 :-)

また、abの指数が高く、かなり離れているように見える場合など、abの間に個別のステップがあまりない場合にも発生します。浮動小数点値はまだ近似値に過ぎず、エンコードできる値の数は有限です。たとえば、_sys.float_info.max_とsys.float_info.max - (2 ** 970)の違いは2進数の1つしかないため、random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)が_sys.float_info.max_を生成する可能性は50〜50です。

_>>> a, b = sys.float_info.max - (2 ** 970), sys.float_info.max
>>> values = [random.uniform(a, b) for _ in range(10000)]
>>> values.count(sys.float_info.max)  # should be roughly 5000
4997
_
13
Martijn Pieters

「数回」では十分ではありません。 10,000では十分ではありません。 random.uniformは、2 ^ 53(9,007,199,254,740,992)の異なる値から選択します。あなたはそれらのtwoに興味があります。そのため、正確に0または1の値を取得する前に、いくつかのquadrillionランダムな値を生成することを期待する必要があります。したがって、それは可能ですが、決して観察しない可能性が非常に高いです。

5
hobbs

承知しました。代わりにuniform(0, 0.001)を試して、すでに正しい方向に進んでいます。境界を制限し続けて、それがより早く発生するようにします。

>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
5e-324
>>> random.uniform(0., 5e-324)
0.0
1
wim

正確な0を表示するために必要な反復回数をカウントするループを試して生成できます(しないでください)。

さらに、Hobbsが述べたように、uniformlyでサンプリングされる値の量は9,007,199,254,740,992です。つまり、0が表示される確率は正確に1/9,007,199,254,740,992です。これは、一般的に言えば、切り上げはaverage 10兆サンプルで0を見つける必要があることを意味します。もちろん、あなたの最初の10回の試みでそれを見つけてください。

値に定義された間隔は括弧で閉じられているため、1を含まないため、1をサンプリングすることは不可能です。

1
Celius Stingher