Im trying to generate random integers with logarithmic distribution. I use the following formula:
idx = Math.floor(Math.log((Math.random() * Math.pow(2.0, max)) + 1.0) / Math.log(2.0));
This works well and produces sequence like this for 1000 iterations (each number represents how many times that index was generated):
[525, 261, 119, 45, 29, 13, 5, 1, 1, 1]
Fiddle
I am now trying to adjust the slope of this distribution so it doesn't drop as quickly and produces something like:
[150, 120, 100, 80, 60, ...]
Blindly playing with coefficients didn't give me what I wanted. Any ideas how to achieve it?
Use rand to generate 1000 random numbers from the uniform distribution on the interval (0,1). rng('default') % For reproducibility u = rand(1000,1); The inversion method relies on the principle that continuous cumulative distribution functions (cdfs) range uniformly over the open interval (0,1).
You can supply your probabilities via the values parameter. You can then use the rvs() method of the distribution object to generate random numbers. As pointed out by Eugene Pakhomov in the comments, you can also pass a p keyword parameter to numpy. random.
Random numbers from a normal distribution can be generated using rnorm() function. We need to specify the number of samples to be generated. We can also specify the mean and standard deviation of the distribution. If not provided, the distribution defaults to 0 mean and 1 standard deviation.
You mention a logarithmic distribution, but it looks like your code is designed to generate a truncated geometric distribution instead, although it is flawed. There is more than one distribution called a logarithmic distribution and none of them are that common. Please clarify if you really do mean one of them.
You compute floor[log_2 U] where U is uniformly distributed from 1 to (2^max)+1. This has a 1/2^max chance to produce max, but you clamp that to max-1. So, you have a 1/2^max chance to produce 0, 2/2^max chance to produce 1, 4/2^max chance to produce 2, ... up to a 1/2 + 1/2^max chance to produce max-1.
Present in your code, but missing from the description in the question, is that you are flipping the computed index around with
idx = (max-idx) - 1
After this, your chance to produce 0 is 1/2 + 1/2^max, and your chance to produce a value of k is 1/2^(k+1).
I think it is a mistake to let U be uniform on [1,2^max+1]. Instead, I think you want U to be uniform on [1,2^max]. Then your chance to generate idx=k is 2^(max-k-1)/((2^max)-1).
idx = Math.floor(Math.log((Math.random()*(Math.pow(2.0, max)-1.0)) + 1.0) / Math.log(2.0));
zmii's comment that you could get a flatter distribution by replacing both 2.0s with a value closer to 1.0 is good. The reason it produced unsatisfactory results for small values of max was that you were sampling uniformly from [1,1.3^max+1] instead of [1,1.3^max]. The extra +1 made a larger difference when max was smaller and the base was smaller. Try the following:
var zmii = 1.3;
idx = Math.floor(Math.log((Math.random()*(Math.pow(zmii, max)-1.0))+1.0) / Math.log(zmii));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With