Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
800 views
in Technique[技术] by (71.8m points)

c# - Generate a random number in a Gaussian Range?

I want to use a random number generator that creates random numbers in a gaussian range where I can define the median by myself. I already asked a similar question here and now I'm using this code:

class RandomGaussian
    {

        private static Random random = new Random();
        private static bool haveNextNextGaussian;
        private static double nextNextGaussian;

        public static double gaussianInRange(double from, double mean, double to)
        {
            if (!(from < mean && mean < to))
                throw new ArgumentOutOfRangeException();

            int p = Convert.ToInt32(random.NextDouble() * 100);
            double retval;
            if (p < (mean * Math.Abs(from - to)))
            {
                double interval1 = (NextGaussian() * (mean - from));
                retval = from + (float)(interval1);
            }
            else
            {
                double interval2 = (NextGaussian() * (to - mean));
                retval = mean + (float)(interval2);
            }
            while (retval < from || retval > to)
            {
                if (retval < from)
                    retval = (from - retval) + from;
                if (retval > to)
                    retval = to - (retval - to);
            }
            return retval;
        }

        private static double NextGaussian()
        {
            if (haveNextNextGaussian)
            {
                haveNextNextGaussian = false;
                return nextNextGaussian;
            }
            else
            {
                double v1, v2, s;
                do
                {
                    v1 = 2 * random.NextDouble() - 1;
                    v2 = 2 * random.NextDouble() - 1;
                    s = v1 * v1 + v2 * v2;
                } while (s >= 1 || s == 0);
                double multiplier = Math.Sqrt(-2 * Math.Log(s) / s);
                nextNextGaussian = v2 * multiplier;
                haveNextNextGaussian = true;
                return v1 * multiplier;
            }
        }
    }

Then to verify the results I plotted them with gaussianInRange(0, 0.5, 1) for n=100000000 enter image description here

As one can see the median is really at 0.5 but there isn't really a curve visible. So what I'm doing wrong?

EDIT

What i want is something like this where I can set the highest probability by myself by passing a value.

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I have similar methods in my Graph generator (had to modify it a bit):

Returns a random floating-point number using a generator function with a specific range:

private double NextFunctional(Func<double, double> func, double from, double to, double height, out double x)
{
    double halfWidth = (to - from) / 2;
    double distance = halfWidth + from;

    x = this.rand.NextDouble() * 2 - 1;// -1 .. 1

    double y = func(x);

    x = halfWidth * x + distance;
    y *= height;

    return y;
}

Gaussian function:

private double Gauss(double x)
{
    // Graph should look better with double-x scale.
    x *= 2;

    double σ = 1 / Math.Sqrt(2 * Math.PI);
    double variance = Math.Pow(σ, 2);
    double exp = -0.5 * Math.Pow(x, 2) / variance;

    double y = 1 / Math.Sqrt(2 * Math.PI * variance) * Math.Pow(Math.E, exp);

    return y;
}

A method that generates a graph using the random numbers:

private void PlotGraph(Graphics g, Pen p, double from, double to, double height)
{
    for (int i = 0; i < 1000; i++)
    {
        double x;
        double y = this.NextFunctional(this.Gauss, from, to, height, out x);

        this.DrawPoint(g, p, x, y);
    }
}

I would rather used a cosine function - it is much faster and pretty close to the gaussian function for your needs:

double x;
double y = this.NextFunctional(a => Math.Cos(a * Math.PI), from, to, height, out x);

The out double x parameter in the NextFunctional() method is there so you can easily test it on your graphs (I use an iterator in my method).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...