random()
他の回答は、の結果は常に厳密に以下であると指摘してい1.0
ます。しかし、それは話の半分にすぎません。
randrange(n)
として計算している場合はint(random() * n)
、を満足するPython浮動小数点数、および正の整数については、それが真実であるため、厳密に。よりも小さいことも知っておく必要があります。x
0.0 <= x < 1.0
n
0.0 <= x * n < n
int(x * n)
n
ここでうまくいかない可能性のあることが2つあります。1つは、を計算するときにx * n
、n
暗黙的にfloatに変換されることです。十分に大きい場合n
、その変換によって値が変わる可能性があります。しかし、Pythonソースを見ると、より小さなint(random() * n)
メソッドのみが使用されていることがわかります(ここと以下では、プラットフォームがIEEE 754 doublesを使用していると想定しています)。これは、floatへの変換が行われる範囲です。情報を失わないことが保証されています(フロートとして正確に表すことができるため)。n
2**53
n
n
うまくいかない可能性のある2番目のことは、乗算の結果x * n
(現在はfloatの積として実行されていることを覚えておいてください)はおそらく正確に表現できないため、丸めが必要になることです。x
に十分近い場合1.0
、丸めによって結果がそれ自体に切り上げられると考えられn
ます。
これが起こらないことを確認するにx
は、(Pythonが実行されているほとんどすべてのマシンで)の可能な最大値のみを考慮する必要があり1 - 2**-53
ます。したがって(1 - 2**-53) * n < n
、正の整数n
については、常に真であるため、これを示す必要がありますrandom() * n <= (1 - 2**-53) * n
。
Proof(Sketch) 。のよう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):上記は、IEEE754binary64演算を想定しています。丸めモードは丸めモードです。多くのマシンでは、その仮定はかなり安全です。ただし、浮動小数点にx87 FPUを使用するx86マシン(たとえば、32ビットLinuxのさまざまなフレーバー)では、乗算で二重丸めが行われる可能性があり、その場合はrandom() * n
切り上げることができますn
。ここでrandom()
、可能な最大値を返します。n
これが発生する可能性のある最小のものはn = 2049
です。詳細については、http://bugs.python.org/issue24546の説明を参照してください。