Georg Schölly
Georg Schölly

Reputation: 126105

What's the correct way to expand a [0,1] interval to [a,b]?

Many random-number generators return floating numbers between 0 and 1.

What's the best and correct way to get integers between a and b?

Upvotes: 4

Views: 3652

Answers (5)

Dr. belisarius
Dr. belisarius

Reputation: 61016

Divide the interval [0,1] in B-A+1 bins

Example A=2, B=5

        [----+----+----+----]
        0    1/4  1/2  3/4  1
Maps to    2    3    4    5

The problem with the formula

 Int (Rnd() * (B-A+1)) + A

is that your Rnd() generation interval is closed on both sides, thus the 0 and the 1 are both possible outputs and the formula gives 6 when the Rnd() is exactly 1.

In a real random distribution (not pseudo), the 1 has probability zero. I think it is safe enough to program something like:

 r=Rnd()
 if r equal 1
     MyInt = B
 else
     MyInt = Int(r * (B-A+1)) + A
 endif

Edit

Just a quick test in Mathematica:

Define our function:

f[a_, b_] :=  If[(r = RandomReal[]) == 1, b, IntegerPart[r (b - a + 1)] + a]

Build a table with 3 10^5 numbers in [1,100]:

table = SortBy[Tally[Table[f[1, 100], {300000}]], First]

Check minimum and maximum:

In[137]:= {Max[First /@ table], Min[First /@ table]}

Out[137]= {100, 1}  

Lets see the distribution:

BarChart[Last /@ SortBy[Tally[Table[f[1, 100], {300000}]], First],
        ChartStyle -> "DarkRainbow"]  

alt text

Upvotes: 6

Tim Pietzcker
Tim Pietzcker

Reputation: 336128

Well, why not just look at how Python does it itself? Read random.py in your installation's lib directory.

After gutting it to only support the behavior of random.randint() (which is what you want) and removing all error checks for non-integer or out-of-bounds arguments, you get:

import random
def randint(start, stop):
    width = stop+1 - start
    return start + int(random.random()*width)

Testing:

>>> l = []
>>> for i in range(2000000):
...     l.append(randint(3,6))
...
>>> l.count(3)
499593
>>> l.count(4)
499359
>>> l.count(5)
501432
>>> l.count(6)
499616
>>>

Upvotes: 1

zaf
zaf

Reputation: 23244

Another way to look at it, where r is your random number in the range 0 to 1:

(1-r)a + rb

As for your additional requirement of the result being an integer, maybe (apart from using built in casting) the modulus operator can help you out. Check out this question and the answer:

Expand a random range from 1–5 to 1–7

Upvotes: 1

Joachim Sauer
Joachim Sauer

Reputation: 308021

Assuming r_a_b is the desired random number between a and b and r_0_1 is a random number between 0 and 1 the following should work just fine:

r_a_b = (r_0_1 * (b-a)) + a

Upvotes: 0

nothrow
nothrow

Reputation: 16168

X = (Rand() * (B - A)) + A

Upvotes: 1

Related Questions