it-swarm.com.de

Eine Zufallszahl zwischen 0,1 und 1,0. Python

Ich versuche, eine Zufallszahl zwischen 0,1 und 1,0 zu generieren. Wir können Rand.randint nicht verwenden, da es Ganzzahlen zurückgibt. Wir haben auch random.uniform(0.1,1.0) versucht, aber einen Wert> = 0.1 und <1.0 können wir dies nicht verwenden, da unsere Suche auch 1.0 enthält.

Hat jemand anderes eine Idee für dieses Problem?

21
user2320923

Wie genau wollen Sie Ihre Zufallszahlen haben? Wenn Sie mit 10 Dezimalstellen zufrieden sind, können Sie random.uniform(0.1, 1.0) einfach auf 10 Stellen runden. Auf diese Weise fügen Sie sowohl 0.1 als auch 1.0 ein:

round(random.uniform(0.1, 1.0), 10)

Um genau zu sein, haben 0.1 und 1.0 nur die Hälfte der Wahrscheinlichkeit im Vergleich zu jeder anderen Zahl dazwischen und natürlich verlieren Sie alle Zufallszahlen, die sich erst nach 10 Ziffern unterscheiden.

18
Elmar Peise

Random.uniform() ist nur:

def uniform(self, a, b):
    "Get a random number in the range [a, b) or [a, b] depending on rounding."
    return a + (b-a) * self.random()

dabei gibt self.random() eine Zufallszahl im Bereich [0.0, 1.0) zurück.

Python (wie auch viele andere Sprachen) verwendet Floating Punkt , um reelle Zahlen darzustellen. Wie 0.1 dargestellt wird, ist ausführlich in den Docs :

from __future__ import division

BPF = 53 # assume IEEE 754 double-precision binary floating-point format
N = BPF + 3
assert 0.1 == 7205759403792794 / 2 ** N

Es erlaubt, eine Zufallszahl in [0.1, 1] (einschließlich) mit randint() zu finden, ohne an Genauigkeit zu verlieren:

n, m = 7205759403792794, 2 ** N
f = randint(n, m) / m

randint(n, m) gibt eine zufällige Ganzzahl in [n, m] (einschließlich) zurück. Daher kann die obige Methode möglicherweise all Gleitkommazahlen in [0.1, 1] zurückgeben.

Eine Alternative besteht darin, die kleinste x zu finden, wie x > 1, und Folgendes zu verwenden:

f = uniform(.1, x)
while f > 1:
    f = uniform(.1, x)

x sollte der kleinste Wert sein, um einen Genauigkeitsverlust zu vermeiden und die Anzahl der Aufrufe von uniform(), z.

import sys
# from itertools import count

# decimal.Decimal(1).next_plus() analog
# x = next(x for i in count(1) for x in [(2**BPF + i) / 2**BPF] if x > 1)
x = 1 + sys.float_info.epsilon

Beide Lösungen bewahren die Gleichmäßigkeit der Zufallsverteilung ( no skew ).

8
jfs

Sie könnten das tun:

>>> import numpy as np
>>> a=.1
>>> b=np.nextafter(1,2)
>>> print(b)
1.0000000000000002
>>> [a+(b-a)*random.random() for i in range(10)]

oder verwende numpys Uniform :

np.random.uniform(low=0.1, high=np.nextafter(1,2), size=1)

nextafter wird die plattformspezifische nächste darstellbare Floating-Point-Nummer in Richtung einer Richtung erzeugen. Die Verwendung von numpy's random.uniform ist vorteilhaft, da eindeutig ist, dass die obere Grenze nicht enthalten ist. 


Bearbeiten 

Es scheint, dass Mark Dickinsons Kommentare richtig sind: Numpys Dokumentation ist falsch bezüglich der Obergrenze für random.uniform, die inklusiv ist oder nicht. 

In der Numpy-Dokumentation wird All values generated will be less than high. angegeben.

Dies kann leicht widerlegt werden:

>>> low=1.0
>>> high=1.0+2**-49
>>> a=np.random.uniform(low=low, high=high, size=10000)
>>> len(np.where(a==high)[0])
640

Das Ergebnis ist auch in diesem begrenzten Bereich nicht einheitlich:

>>> for e in sorted(set(a)):
...    print('{:.16e}: {}'.format(e,len(np.where(a==e)[0])))
... 
1.0000000000000000e+00: 652
1.0000000000000002e+00: 1215
1.0000000000000004e+00: 1249
1.0000000000000007e+00: 1288
1.0000000000000009e+00: 1245
1.0000000000000011e+00: 1241
1.0000000000000013e+00: 1228
1.0000000000000016e+00: 1242
1.0000000000000018e+00: 640

Ich denke jedoch, dass die Kombination der Kommentare von J. F. Sebastian und Mark Dickinson funktioniert:

import numpy as np
import random 

def Rand_range(low=0,high=1,size=1):
    a=np.nextafter(low,float('-inf'))
    b=np.nextafter(high,float('inf'))
    def r():
        def rn(): 
            return a+(b-a)*random.random()

        _rtr=rn()
        while  _rtr > high:
            _rtr=rn()
        if _rtr<low: 
            _rtr=low
        return _rtr     
    return [r() for i in range(size)]

Wenn Sie mit der minimalen Streuung von Werten in Marks Kommentar laufen, so dass nur sehr wenige diskrete Gleitkommawerte vorhanden sind

l,h=1,1+2**-48
s=10000
rands=Rand_range(l,h,s)    
se=sorted(set(rands))
if len(se)<25:
    for i,e in enumerate(se,1):
        c=rands.count(e)
        note=''
        if e==l: note='low value end point'
        if e==h: note='high value end point'
        print ('{:>2} {:.16e} {:,}, {:.4%} {}'.format(i, e, c, c/s,note))

Es ergibt die gewünschte Gleichverteilung einschließlich der Endpunkte:

 1 1.0000000000000000e+00 589, 5.8900% low value end point
 2 1.0000000000000002e+00 544, 5.4400% 
 3 1.0000000000000004e+00 612, 6.1200% 
 4 1.0000000000000007e+00 569, 5.6900% 
 5 1.0000000000000009e+00 593, 5.9300% 
 6 1.0000000000000011e+00 580, 5.8000% 
 7 1.0000000000000013e+00 565, 5.6500% 
 8 1.0000000000000016e+00 584, 5.8400% 
 9 1.0000000000000018e+00 603, 6.0300% 
10 1.0000000000000020e+00 589, 5.8900% 
11 1.0000000000000022e+00 597, 5.9700% 
12 1.0000000000000024e+00 591, 5.9100% 
13 1.0000000000000027e+00 572, 5.7200% 
14 1.0000000000000029e+00 619, 6.1900% 
15 1.0000000000000031e+00 593, 5.9300% 
16 1.0000000000000033e+00 592, 5.9200% 
17 1.0000000000000036e+00 608, 6.0800% high value end point

Bei den vom OP angeforderten Werten wird auch eine gleichmäßige Verteilung erzeugt:

import matplotlib.pyplot as plt

l,h=.1,1  
s=10000
bin_count=20
rands=Rand_range(l,h,s)  
count, bins, ignored = plt.hist(np.array(rands),bin_count)   
plt.plot(bins, np.ones_like(bins)*s/bin_count, linewidth=2, color='r')
plt.show()   

Ausgabe

uniform

7
dawg

Mit den Informationen, die Sie bisher gegeben haben (einschließlich der Kommentare), kann ich immer noch nicht erkennen, wie die Universität Ihr Programm so testen wird, dass es einen Unterschied macht, ob 1.0 erscheint oder nicht. (Ich meine, wenn Sie ZufallsFloats generieren müssen, wie können sie dann verlangen, dass jeder bestimmte Wert erscheint?)

OK, also die Verrücktheit Ihrer Anforderungen beiseite stellen:

Die Tatsache, dass die Untergrenze für die zufälligen Gleitkommazahlen größer als 0 ist, gibt Ihnen eine ärgerlich elegante Möglichkeit, random.random zu verwenden, die Rückgabewerte im Intervall [0.0, 1.0) garantiert: Rufen Sie einfach random.random auf, und geben Sie Werte unter 0,1 weg. außer 0,0. Wenn Sie tatsächlich 0.0 erhalten, geben Sie stattdessen 1.0 ein.

So etwas wie

from random import random

def myRandom():
    while True:
        r = random()
        if r >= 0.1:
            return r
        if r == 0.0:
            return 1.0
3
John Y

Sie können random.randint einfach mit diesem Trick verwenden:

>>> float(random.randint(1000,10000)) / 10000
0.4362

wenn Sie mehr Dezimalstellen wünschen, ändern Sie einfach das Intervall in:

(1000, 10000) 4 Ziffern (10000,100000) 5 Ziffern Usw

2
jabaldonedo

Die Standardmethode wäre random.random() * 0.9 + 0.1 (random.uniform() tut intern genau dies). Dies gibt Zahlen zwischen 0,1 und 1,0 ohne oberen Rand zurück.

Aber warte! 0,1 (aka ¹/₁₀) hat keine eindeutige Binärdarstellung (als ⅓ in Dezimalzahl)! Sie erhalten also sowieso keine echte 0,1, weil der Computer sie intern nicht darstellen kann. Es tut uns leid ;-)

1
Alfe

Können Sie random.random() nicht verwenden? Dies gibt eine Zahl zwischen 0,0 und 1,0, obwohl Sie leicht einen Weg einrichten können, um dies zu umgehen.

import random
def randomForMe():
    number = random.random()
    number = round(number, 1)
    if (number == 0):
        number = 0.1

Dieser Code würde Ihnen eine Zahl zwischen 0,1 und 1,0 (einschließlich 0,1 und 1,0) geben. Hoffe das hilft.

* Ich nahm an, Sie wollten nur Zehntel-Nummern. Wenn Sie es anders wollen, wo ich round(number, 1) eingegeben habe, 1 in 2 für Hundertstel, 3 für Tausendstel usw. ändern.

1
erdekhayser

Versuchen Sie Random.randint (1, 10) /100.0

0
user2844536

Laut Python 3.0 Dokumentation :

random. uniform (a, b) Geben Sie eine zufällige Gleitkommazahl N zurück, sodass a <= N <= b für a <= b und b <= N <= a für b <a.

Daher beinhaltet random.uniform() tatsächlich die Obergrenze, zumindest für Python 3.0.

BEARBEITEN: Wie @Blender ausgeführt hat, scheint die Dokumentation für Python 3.0 mit dem Quellcode in diesem Punkt nicht übereinstimmen.

EDIT 2: Wie von @ MarkDickinson ausgeführt, hatte ich ungewollt eine Verknüpfung zur Python 3.0-Dokumentation anstelle der neuesten Python 3-Dokumentation hier , die wie folgt lautet:

random. uniform (a, b) Geben Sie eine zufällige Gleitkommazahl N wie an, dass a <= N <= b für a <= b und b <= N <= a für b <a. 

Der Endpunktwert B kann in dem Bereich enthalten sein oder nicht, abhängig von der Gleitpunktrundung In der Gleichung a + (b-a) * random ().

0
Simon

In numpy können Sie Folgendes tun:

import numpy
numpy.random.uniform(0.1, numpy.nextafter(1, 2))
0
Mitar