Function in Python to generate random float numbers in range [a, b) – without upper bound

Question:

A function random.random() generates random float numbers in range [0, 1), a half-open range. On the other hand, a function uniform(a, b) generates numbers in range [a, b] or [a, b) (cannot be specified explicitly) according docs. I am looking for Python function to generate random float numbers only in range [a, b) (without upper bound).

I looked at several questions e.g. to this one but I didn’t find answer.

Asked By: illuminato

||

Answers:

import random
def rand_float(a, b):
    return random.random() * (b-a) + a

This function should work. It utilizes the fact that random.random() returns [0, 1) and just scales it up according to the desired range, then applying an offset so that it will begin in the correct place.

Example:

print(rand_float(1, 5.3)) # could give 3.6544643 or 4.2999 but not 5.3

This doesn’t take into account floating-point precision issues, but for most cases it will work.

Answered By: Luke Borowy

Unless your b is exceedingly close to a, it is extremely unlikely that b will ever be the exact output of your random number generator (unless the generator is itself bad), so I would recommend accepting a tiny bias and just returning any relevant value, e.g. a, if the result happens to be b. For example, assuming gen(a, b) is how you are generating values between a and b,

def closed_open_rand(a, b):
    r = gen(a, b)
    if r == b:
        return a
    return r

This will introduce a tiny bias towards the value a that you probably don’t care about. If you really care about avoiding this tiny bias, you can instead give up determinism:

def closed_open_rand(a, b):
    while (r := gen(a, b)) == b:
        pass
    return r

This method avoids the tiny bias, but could theoretically be an infinite loop if your generator is bad.

If you really care about both avoiding tiny bias and maintaining determinism, then you need to look into more sophisticated methods.

Answered By: mCoding

You could do something like this:

from random import choice
from numpy import arange

start = 0
stop = 1
precision = 0.00001
choice(arange(start, stop, precision))

where choice picks randomly a number from a float range. Stop is excluded since it uses a range.

Answered By: Andreas

From the documentation, it looks like numpy.random.uniform actually does what you want:

Samples are uniformly distributed over the half-open interval [low, high) (includes low, but excludes high)

Solution:

import numpy as np

x = np.random.uniform(a, b)
Answered By: Bill

If you have a random function such as uniform() which may give a half-open or fully-open range (and you don’t know which), probably the simplest way to ensure it gives a half-open range is just to filter out the high values.

In other words, something like:

def half_open_uniform(a, b):
    result = uniform(a, b)
    while result == b:
        result = uniform(a, b)
    return result

If uniform() already returns a half-open value, the while loop will never run and you’ll get back a value you want.

If the value it returns is fully-open and your upper and lower bounds have a decent spread, the vast majority of cases will also not activate the while loop.

If the upper and lower bounds are very close, the probability of getting the upper bound increases but, even then, it will most likely just run once.

If the two bounds are identical, that probabilty rises sharply to 100%. But calling something like half_open_uniform(1, 1) can be caught with a simple pre-check at the start of the function, probably raising an exception.

Answered By: paxdiablo
Categories: questions Tags:
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.