Skip to content Skip to sidebar Skip to footer

Generate Random Number Between 0.1 And 1.0. Python

I'm trying to generate a random number between 0.1 and 1.0. We can't use rand.randint because it returns integers. We have also tried random.uniform(0.1,1.0), but it returns a valu

Solution 1:

How "accurate" do you want your random numbers? If you're happy with, say, 10 decimal digits, you can just round random.uniform(0.1, 1.0) to 10 digits. That way you will include both 0.1 and 1.0:

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

To be precise, 0.1 and 1.0 will have only half of the probability compared to any other number in between and, of course, you loose all random numbers that differ only after 10 digits.

Solution 2:

You could do this:

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

or, use numpy's uniform:

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

nextafter will produce the platform specific next representable floating pointing number towards a direction. Using numpy's random.uniform is advantageous because it is unambiguous that it does not include the upper bound.


Edit

It does appear that Mark Dickinson's comments is correct: Numpy's documentation is incorrect regarding the upper bound to random.uniform being inclusive or not.

The Numpy documentation states All values generated will be less than high.

This is easily disproved:

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

Nor is the result uniform over this limited range:

>>>for e insorted(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

However, combining J.F. Sebastian and Mark Dickinson's comments, I think this works:

import numpy as np
import random 

defrand_range(low=0,high=1,size=1):
    a=np.nextafter(low,float('-inf'))
    b=np.nextafter(high,float('inf'))
    defr():
        defrn(): 
            return a+(b-a)*random.random()

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

If run with the minimal spread of values in Mark's comment such that there are very few discrete floating point values:

l,h=1,1+2**-48
s=10000
rands=rand_range(l,h,s)    
se=sorted(set(rands))
iflen(se)<25:
    for i,e inenumerate(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))

It produces the desired uniform distribution inclusive of end points:

11.0000000000000000e+00589, 5.8900% low value end point
 21.0000000000000002e+00544, 5.4400% 
 31.0000000000000004e+00612, 6.1200% 
 41.0000000000000007e+00569, 5.6900% 
 51.0000000000000009e+00593, 5.9300% 
 61.0000000000000011e+00580, 5.8000% 
 71.0000000000000013e+00565, 5.6500% 
 81.0000000000000016e+00584, 5.8400% 
 91.0000000000000018e+00603, 6.0300% 
101.0000000000000020e+00589, 5.8900% 
111.0000000000000022e+00597, 5.9700% 
121.0000000000000024e+00591, 5.9100% 
131.0000000000000027e+00572, 5.7200% 
141.0000000000000029e+00619, 6.1900% 
151.0000000000000031e+00593, 5.9300% 
161.0000000000000033e+00592, 5.9200% 
171.0000000000000036e+00608, 6.0800% high value end point

On the values requested by the OP, it also produces a uniform distribution:

import matplotlib.pyplotas 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()   

Output

uniform

Solution 3:

Random.uniform() is just:

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

where self.random() returns a random number in the range [0.0, 1.0).

Python (as well as many other languages) uses floating point to represent real numbers. How 0.1 is represented is described in detail in the docs:

from __future__ import division

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

It allows to find a random number in [0.1, 1] (inclusive) using randint() without losing precision:

n, m = 7205759403792794, 2 ** Nf= randint(n, m) / m

randint(n, m) returns a random integer in [n, m] (inclusive) therefore the above method can potentially return all floating points numbers in [0.1, 1].

An alternative is to find the smallest x such that x > 1 and use:

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

x should be the smallest value to avoid losing precision and to reduce number of calls to uniform() e.g.:

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

Both solutions preserve uniformness of the random distribution (no skew).

Solution 4:

With the information you've given (including comments thus far), I still fail to see how the university is going to test your program such that it will make a difference if 1.0 appears or not. (I mean, if you're required to generate random floats, how can they require that any particular value appears?)

OK, so putting the craziness of your requirements aside:

The fact that the lower bound for your random floats is higher than 0 gives you a disturbingly elegant way to use random.random, which guarantees return values in the interval [0.0, 1.0): Simply keep calling random.random, throwing away any values less than 0.1, except 0.0. If you actually get 0.0, return 1.0 instead.

So something like

from random import random

defmyRandom():
    whileTrue:
        r = random()
        if r >= 0.1:
            return r
        if r == 0.0:
            return1.0

Solution 5:

You can use random.randint simply by doing this trick:

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

if you want more decimals, just change the interval to:

(1000,10000) 4 digits (10000,100000) 5 digits etc

Post a Comment for "Generate Random Number Between 0.1 And 1.0. Python"