简体   繁体   中英

How to generate random positive floating point numbers with normal distribution from 0 up to a given ceiling?

I need to generate a number of float numbers with approximately normal distribution over a range from 0 to a specific ceiling.

I've searched on stack overflow and found similar questions for other languages, but none for .net core.

internal List<float> function(int ceiling, int repetitions)
{
    List<float> list = new List<float>();
    for (int i = 0; i<= repetitions;i++)
    {
         list.Add(Random.nextFloat() * ceiling);
    }
    return list;
}

I expect the function to return a list of random positive float numbers, in range from 0 to a given ceiling with at least approximately normal distribution.

If you're seeking something "at least approximately normal" with bounds at 0 and ceiling , summing three uniforms will yield a result which is symmetric, bell-shaped, and bounded, and can subsequently be rescaled to any range you wish. I'm not a C# programmer, but if you have a PRNG named prng :

(prng.NextDouble() + prng.NextDouble() + prng.NextDouble()) * ceiling / 3.0

will yield a result in the range [0, ceiling] . Here's what 100,000 observations look like with ceiling set to 3:

3个uniforms直方图之和是对称的、钟形的、有界的

You can generalize this to sum k uniforms and replace the 3 by k in the divisor for the rescaling. The larger k is, the closer this will get to normality by the central limit theorem, but since you don't seem to be asking for actual normals (which don't have a bounded range anyway) that quickly gets into diminishing returns.

Note that while this approach uses multiple uniforms, it is computationally relatively efficient because it avoids transcendental functions.

Well, you could use truncated normal together with taking absolute values to make result positive.

Along the lines

double R = 10.0; // upper value of the truncated normal

var seed = 31234567;
Random rng = new Random( seed );

double u1 = rng.NextDouble();
double u2 = rng.NextDouble();

double phi = 2.0*Math.PI*u2;
double r   = Math.Sqrt(-2.0*Math.Log(1.0 - u1*(1.0 - Math.Exp(-R*R/2.0))));

return new Tuple<double,double>(Math.Abs(r*Math.Cos(phi)), Math.Abs(r*Math.Sin(phi)));

Code above shall return couple of sampled values in the interval from 0 to R which looks like truncated gaussian. You could compare with Box-Muller for standard gaussain sampling

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM