Kann random.uniform (0,1) jemals 0 oder 1 erzeugen?

9

In der Dokumentation heißt es, dass es eine Chance uniform(0,1)gibt, die Werte 0und zu generieren 1.

Ich bin uniform(0, 1)10000 Mal gelaufen , aber es hat nie Null produziert. Auch im Fall von uniform(0, 0.001).

Kann random.uniform(0,1)jemals erzeugen 0oder 1?

Venkatesh Gandi
quelle
3
Es ist theoretisch möglich, wird aber praktisch nie passieren. Mathematisch ein Standard einheitlicher Zufallsvariable kann im Intervall von 0 bis 1 auf jedem beliebigen Wert annehmen , wenn X ~ U(0,1), dann das P(X=x)ist fast sicher 0, für alle Werte von x. (Dies liegt daran, dass das Intervall unendlich viele mögliche Werte enthält.) Wenn Sie genau 0 oder 1 suchen, sollten Sie eine andere Funktion verwenden - zum Beispielrandom.choice
pault
1
@pault hat mit ziemlicher Sicherheit eine sehr spezifische Bedeutung in der Mathematik, was hier nicht wirklich sinnvoll ist, da wir eine diskrete Verteilung haben, kein kontinuierliches Intervall. Es gibt nur eine begrenzte Anzahl von Floats zwischen 0 und 1.
wim
2
@pault Warum sprichst du also mathematisch, wenn das OP nach der Implementierung von fragt random.uniform?
wim
1
Wenn diese Dokumentation korrekt ist, bin ich neugierig, wie sie möglicherweise sowohl 0 als auch 1 erzeugt. Scheint, als wäre [0, 1) viel einfacher (so Math.random()funktioniert das beispielsweise in JavaScript).
Ry-
1
50 Punkte Kopfgeld für die erste Person, die einen zufälligen random.uniform(0, 1)
Startwert veröffentlicht,

Antworten:

13

uniform(0, 1)kann produzieren 0, aber es wird nie produzieren 1.

Die Dokumentation sagt Ihnen , dass der Endpunkt b könnte in den Werten erzeugt aufgenommen werden:

Der Endpunktwert bkann abhängig von der Gleitkomma-Rundung in der Gleichung in dem Bereich enthalten sein oder nicht a + (b-a) * random().

Denn uniform(0, 1)die Formel 0 + (1-0) * random(), vereinfacht auf 1 * random(), müsste in der Lage sein, 1genau zu produzieren . Das würde nur passieren, wenn random.random()1.0 exactly. However,random () *never* produces1.0` ist.

Zitieren der random.random()Dokumentation :

Gibt die nächste zufällige Gleitkommazahl im Bereich [0.0, 1.0] zurück.

Die Notation [..., ...)bedeutet, dass der erste Wert Teil aller möglichen Werte ist, der zweite jedoch nicht. random.random()wird höchstens Werte sehr nahe an erzeugen 1.0. Pythons floatTyp ist ein IEEE 754 base64-Gleitkommawert , der eine Anzahl von binären Brüchen (1/2, 1/4, 1/5 usw.) codiert , aus denen der Wert besteht, und der erzeugte Wert random.random()ist einfach die Summe von a zufällige Auswahl dieser 53 solcher Fraktionen von 2 ** -1(1/2) bis 2 ** -53(1/9007199254740992).

Da es jedoch Werte sehr nahe produzieren kann 1.0, zusammen mit Rundungsfehlern , die auftreten , wenn Sie mehrfach Punkt nubmers schwimmen, Sie können produzieren bfür einige Werte von aund b. Aber 0und 1gehören nicht zu diesen Werten.

Beachten Sie, dass random.random() dies 0,0 erzeugen kann und daher aimmer in den möglichen Werten für random.uniform()( a + (b - a) * 0 == a) enthalten ist. Da es 2 ** 53unterschiedliche Werte gibt, random.random()die erzeugen können (alle möglichen Kombinationen dieser 53 binären Brüche), gibt es nur eine 1-in- 2 ** 53Chance (also 1 in 9007199254740992), dass dies jemals passiert.

Der höchstmögliche Wert, der erzeugt werden random.random()kann, ist also 1 - (2 ** -53): Wählen Sie einfach einen Wert, der klein genug ist b - a, damit die Rundung einsetzt, wenn sie mit höheren random.random()Werten multipliziert wird . Je kleiner b - aist, desto größer ist die Wahrscheinlichkeit, dass dies geschieht:

>>> 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

Wenn Sie treffen b = 0.0, haben wir 1023 Mal geteilt. Der obige Wert bedeutet, dass wir nach 1019 Teilungen Glück hatten. Der höchste Wert, den ich bisher gefunden habe (Ausführen der obigen Funktion in einer Schleife mit max()), ist 8.095e-320(1008 Teilungen), aber es gibt wahrscheinlich höhere Werte. Es ist alles ein Glücksspiel. :-)

Es kann auch passieren, wenn es nicht viele diskrete Schritte zwischen aund gibt b, wie wenn aund beinen hohen Exponenten haben und daher weit auseinander liegen. Gleitkommawerte sind immer noch nur Näherungswerte, und die Anzahl der Werte, die sie codieren können, ist endlich. Zum Beispiel gibt es nur 1 binären Bruchteil der Differenz zwischen sys.float_info.maxund sys.float_info.max - (2 ** 970), so dass eine 50-50-Chance random.uniform(sys.float_info.max - (2 ** 970), sys.float_info.max)ergibt sys.float_info.max:

>>> 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
Martijn Pieters
quelle
5

"Mehrmals" ist nicht genug. 10.000 sind nicht genug. random.uniformwählt aus 2 ^ 53 (9.007.199.254.740.992) verschiedene Werte aus. Sie interessieren sich für zwei von ihnen. Daher sollten Sie damit rechnen, mehrere Billiarden Zufallswerte zu generieren , bevor Sie einen Wert erhalten, der genau 0 oder 1 ist. Es ist also möglich, aber es ist sehr wahrscheinlich, dass Sie ihn niemals beobachten werden.

Hobbs
quelle
2
Denn uniform(0, 1)es ist unmöglich , 1als Ergebnis zu produzieren . Das liegt daran, dass die Funktion einfach definiert ist def uniform(a, b): return a + (b - a) * random()und random()niemals produzieren kann 1.0.
Martijn Pieters
2
@MartijnPieters Ich glaube, Sie haben Recht, und ich habe Ihre Antwort positiv bewertet. Ich vermutete das auch, war mir aber nicht sicher, und es war abgesehen von dem Hauptschwerpunkt meiner Antwort, also ließ ich es sein :)
Hobbs
1

Sie können versuchen, eine Schleife zu generieren, die die Anzahl der Iterationen zählt, die erforderlich sind, um eine exakte 0 anzuzeigen (nicht).

Wie Hobbs feststellte, beträgt die Menge der uniformlyabgetasteten Werte 9.007.199.254.740.992. Dies bedeutet, dass die Wahrscheinlichkeit, eine 0 zu sehen, genau 1 / 9,007,199,254,740,992 beträgt. Was im Allgemeinen und Aufrundung bedeutet, dass Sie durchschnittlich 10 Billiarden Proben benötigen , um eine 0 zu finden. Natürlich finden Sie sie möglicherweise bei Ihren ersten 10 Versuchen oder nie.

Das Abtasten einer 1 ist unmöglich, da das für die Werte definierte Intervall mit einer Klammer geschlossen wird und daher 1 nicht enthält.

Celius Stingher
quelle
1

Sicher. Sie waren bereits auf dem richtigen Weg, es uniform(0, 0.001)stattdessen zu versuchen . Beschränken Sie die Grenzen einfach so weit, dass dies früher geschieht.

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