4

Heyho,

I'm trying to generate a random number between 0.0 and 1.0 with exponential/negative exponential distribution. There is an article, which tells that you have to get the "quantile function". But the results are still greater than 1.0. So I would need to scale my equation somehow.

My goal is to generate a random number in a range, where for example higher/lower values have a higher probability. (The distribution should be scalable)

Related questions(don't truncate the result to [0,1]):

Community
  • 1
  • 1
maxammann
  • 1,018
  • 3
  • 11
  • 17
  • https://en.wikipedia.org/wiki/Exponential_distribution#Generating_exponential_variates – Oliver Charlesworth Dec 04 '13 at 21:10
  • (Of course, an exponential distribution has an infinite tail, so you'll have to approximate...) – Oliver Charlesworth Dec 04 '13 at 21:10
  • @OliCharlesworth is there maybe an other distribution (with [0,1]) which behaves like an exponential, the higher the x, the higher the probability of a higher y or the higher the x, the lower the probability of a higher y? – maxammann Dec 04 '13 at 21:14

3 Answers3

7

The negative exponential distribution has support on the range [0, ∞), so I'm interpreting your question as a request for a truncated negative exponential. The Cumulative Distribution Function for such a beast with lower limit l >= 0, upper limit h > l, and rate λ is

F(x) = (exp(-λl) - exp(-λx)) / (exp(-λl) - exp(-λh))

We can find the inversion by setting this equal to U, a uniform(0,1) random number, and solving for x:

X = -ln(exp(-λl) - (exp(-λl) - exp(-λh)) * U) / λ

Since you specified lower and upper limits of 0 and 1, respectively, this reduces to

X = -ln(1 - (1 - exp(-λ)) * U) / λ

Replace U with a call to your favorite U(0,1) generator and that's your algorithm for generating X's with the desired distribution.

Here's a histogram of 10,000 values generated with λ = 5. Smaller values of λ give a flatter distribution, larger values show a more rapid exponential drop off.

10,000 truncated exponentials with lambda = 5

pjs
  • 18,696
  • 4
  • 27
  • 56
  • Thanks man :D I think the hardest task was to get what I wanted :D (also because I wasn't sure either), but this is exactly what I was looking for! (You can also test it over here: http://www.petrileskinen.fi/random/randomDistribution.html) Which tool did you use to generate the histogram? – maxammann Dec 05 '13 at 20:08
  • I use JMP for a lot of my statistical analyses. Glad I could help. – pjs Dec 05 '13 at 20:21
2

Based on the comment that you want both lower and higher numbers to have a higher likelihood:

// let u,v be random real numbers from [1, 10]
x = log(u) // x is from 0.0 to 1.0, with higher probability getting higher values.
y = 1 - log(v) // y is from 0.0 to 1.0, with higher probability of getting lower values.
if abs(x - 0.5) > abs(y - 0.5):
    return x
else:
    return y

This is a bit hacky, but it makes it extremely unlikely to get a value exactly in the middle 0.5 and likely to get the edge values. It seems to fit your requirements though.

EDIT: It could use some fine tuning when x == y. You could use another random choice to determine which to select in that case:

if x == y:
    // let w be a random number either 1 or 2.
    if w == 1:
        return x
    else:
        return y

Additionally, if the application calls for this function to be a bit more or less polar, it can be adapted to do so:

// let u,v be random real numbers from [1, K] where K > 1 
// and let j be a real number given by log(K).  j is selected by the function's caller.
x = log(u) / j
y = (1 - log(v)) / j
// The remainder of the formula is identical.

By using a value like 2 for j, K = 100 and thus is more likely to be a polar value. If a value less than 10 is used for j, it will be less likely to be a polar value. In this way you can control the "slope" of the function.

BlackVegetable
  • 12,594
  • 8
  • 50
  • 82
  • possible, but not very flexible :P, the random generator is for a game, so it should be quite scalable – maxammann Dec 04 '13 at 21:38
  • In what way do you want it to "flex"? I'll bet I could make it work -- just let me know. – BlackVegetable Dec 04 '13 at 21:38
  • So basicall I want to have a function where I can modify different constants like the slope. By scaling this slope, the probability of higher/lower results changes – maxammann Dec 04 '13 at 21:45
  • I have modified this answer such that you could have a function provide a constant to determine how polar to make this function. A value of j > 1 will make it more polar. A value of j < 1 will make it less polar. – BlackVegetable Dec 04 '13 at 21:52
  • k, I first need to think about this :D I'll come then back to you :D – maxammann Dec 04 '13 at 21:55
1

You could just use Math.random() to generate a random double between 0.0 and 1.0, and then simply take the square root of the result. That would achieve the desired effect ("My goal is to generate a random number in a range, where for example higher values have a higher probability.)

Or is that not what you want, because it's not specifically exponential distribution, but I guess polynomial with degree two?

asaini007
  • 858
  • 5
  • 19
  • This would work, I also already tried it, the problem is only that I also want that lower values can have a higher probability – maxammann Dec 04 '13 at 21:22
  • I tried this with the equation f(x) = -x² + 1, but somehow the test results didn't really match. It was more linar than exponential – maxammann Dec 04 '13 at 21:24
  • Do you want the lower values to have a high probability - because your question states the opposite. – asaini007 Dec 04 '13 at 21:26
  • Basically I want to be able to do both. It should be also flexible, so it's much more probable to get a higher result – maxammann Dec 04 '13 at 21:31
  • would it be possible to scale the output if you take the square root of Math.random()? So the distribution changes and higher values have a much higher probability than before. – maxammann Dec 05 '13 at 16:37