Andere Antworten haben darauf hingewiesen, dass das Ergebnis der random()
ist immer streng weniger als 1.0
; Aber das ist nur die halbe Geschichte.
Wenn Sie randrange(n)
als int(random() * n)
Berechnen Sie auch Notwendigkeit, dass für jeden Python Schwimmer wissen x
0.0 <= x < 1.0
erfüllt werden kann und eine positive ganze Zahl n
, es ist wahr, dass 0.0 <= x * n < n
, so dass int(x * n)
ist strikt kleiner als n
.
Es gibt zwei Dinge, die hier schief gehen könnten: Erstens, wenn wir x * n
berechnen, wird n
implizit in einen Float konvertiert. Für groß genug n
kann diese Konvertierung den Wert ändern.Aber wenn Sie sich die Python-Quelle ansehen, werden Sie sehen, dass sie nur die int(random() * n)
-Methode für n
kleiner als 2**53
verwendet (hier und im Folgenden nehme ich an, dass die Plattform IEEE 754-Doubles verwendet), das ist der Bereich, in dem die Konvertierung von n
zu einem Schwimmer ist garantiert, keine Informationen zu verlieren (weil n
kann genau wie ein Schwimmer dargestellt werden).
Die zweite Sache, die schief gehen könnte ist, dass das Ergebnis der Multiplikation x * n
(die jetzt als Produkt von Floats durchgeführt wird, nicht vergessen) wird wahrscheinlich nicht genau darstellbar sein, so dass es einige Rundungen beteiligt sein wird. Wenn x
nah genug an 1.0
ist, ist es denkbar, dass die Rundung das Ergebnis auf n
selbst runden wird.
Um zu sehen, dass dies nicht passieren kann, müssen wir nur den größtmöglichen Wert für x
berücksichtigen, was (auf fast allen Rechnern, auf denen Python läuft) 1 - 2**-53
ist. Also müssen wir zeigen, dass (1 - 2**-53) * n < n
für unsere positive ganze Zahl n
, da es immer wahr sein wird, dass random() * n <= (1 - 2**-53) * n
.
Proof (Skizze) Lassen Sie k
k
so dass 2**(k-1) < n <= 2**k
die eindeutige ganze Zahl sein. Dann ist der nächste Schwimmer von n
n - 2**(k-53)
. Wir müssen zeigen, dass n*(1-2**53)
(d. H. Der tatsächliche, nicht gerundete Wert des Produkts) näher an n - 2**(k-53)
ist als an n
, so dass es immer abgerundet wird. Aber eine kleine Arithmetik zeigt, dass der Abstand von n*(1-2**-53)
zu n
2**-53 * n
ist, während der Abstand von n*(1-2**-53)
zu n - 2**(k-53)
(2**k - n) * 2**-53
ist. Aber 2**k - n < n
(weil wir wählten k
so dass 2**(k-1) < n
), so dass das Produkt ist näher an n - 2**(k-53)
, so dass es wird nach unten geht gerundet (vorausgesetzt, das heißt, dass die Plattform eine Form von runden zu nächsten tut) .
So sind wir sicher. Puh!
Addendum (2015.07.04): Die oben annimmt IEEE 754 binary64 Arithmetik, mit runden Bindern-to-even Rundungsmodus. Auf vielen Maschinen ist diese Annahme ziemlich sicher. Auf x86-Rechnern, die die FPU x87 für Fließkomma verwenden (z. B. verschiedene Varianten von 32-Bit-Linux), besteht jedoch die Möglichkeit, double rounding in der Multiplikation zu verwenden, was es möglich macht, um zu zu n
zu runden in dem Fall, in dem random()
den größtmöglichen Wert zurückgibt. Die kleinste solche n
, für die dies passieren kann, ist . Siehe die Diskussion unter http://bugs.python.org/issue24546 für mehr.
Übrigens, 'int (random.random() * n)' ist immer noch keine perfekte Methode, um ganze Zahlen zu erzeugen, die gleichmäßig in 'range (n)' verteilt sind; Es gibt einen Bias, der für kleine "n" bedeutungslos ist, aber signifikant wird, wenn "n" groß wird. Ich habe dafür einen Python-Bug unter http://bugs.python.org/issue9025 geöffnet. –
@Mark Dickinson: Danke! Das ist faszinierend. –
@ Mark Dickinson: [Dieser Fehler ist ab heute behoben] (http://docs.python.org/dev/whatsnew/3.2.html#random). –