197

Is it possible to generate a random number between 2 doubles?

Example:

public double GetRandomeNumber(double minimum, double maximum)
{
    return Random.NextDouble(minimum, maximum) 
}

Then I call it with the following:

double result = GetRandomNumber(1.23, 5.34);

Any thoughts would be appreciated.

VansFannel
  • 45,055
  • 107
  • 359
  • 626
CodeLikeBeaker
  • 20,682
  • 14
  • 79
  • 108

13 Answers13

408

Yes.

Random.NextDouble returns a double between 0 and 1. You then multiply that by the range you need to go into (difference between maximum and minimum) and then add that to the base (minimum).

public double GetRandomNumber(double minimum, double maximum)
{ 
    Random random = new Random();
    return random.NextDouble() * (maximum - minimum) + minimum;
}

Real code should have random be a static member. This will save the cost of creating the random number generator, and will enable you to call GetRandomNumber very frequently. Since we are initializing a new RNG with every call, if you call quick enough that the system time doesn't change between calls the RNG will get seeded with the exact same timestamp, and generate the same stream of random numbers.

Michael
  • 54,279
  • 5
  • 125
  • 144
  • 46
    Just watch out if you call GetRandomNumber() in a loop as it will generate the same value over and over – John Rasch Jun 30 '09 at 17:25
  • 1
    return new Random().NextDouble() * (maximum - minimum) + minimum; is how I'd return it since I'm not using "random" anywhere else in that function. – Zack Jun 30 '09 at 17:47
  • 1
    @Zack - Remember, though that the seed value is likely going to be the same if you use GetRandomNumber() repeatedly in a loop. If you call GetRandomNumber no more than once per millisecond, you should be ok. If you notice your random numbers are repeating, you'll know why. – Charlie Salts Jun 30 '09 at 20:15
  • 13
    Could be a nice extention method, `public double GetRandomNumber(this Random random, double minimum, double maximum) {...}` – Johnny5 Nov 16 '11 at 15:15
  • 6
    Keep in mind that since Random.NextDouble never returns 1.0, this function will also never equal the maximum number. – Matthew Jan 26 '12 at 20:46
  • 6
    I suggest to put as a seed new Random((int)DateTime.Now.Ticks) this should make it "more random" even in quick loops. – Daniel Skowroński Aug 22 '12 at 20:03
  • 1
    Note this doesn't handle special values (infinity, etc.). Also, and more problematic IMHO, the distribution can be very bad if (maximum - minimum) is a big number. – Simon Mourier Feb 04 '13 at 16:50
  • 6
    This does not work if min value is double.MinValue and max value is double.MaxValue. Any suggestions on how to handle this use case? – Gene S Mar 30 '13 at 23:39
  • 3
    @DanielSkowroński I think your suggestion is uneccessary as [the documentation](http://msdn.microsoft.com/en-us/library/h343ddh9.aspx) implies similar functionality by default. And you should not be creating a new Random instance inside the loop, it should be created once and reused. – Sam Holder Apr 08 '14 at 09:50
  • 1
    @JohnRasch I added a new answer to cover this specific case: http://stackoverflow.com/a/22992590/114029 and just now I noticed that this answer also talks about it in the end. :) – Leniel Maccaferri Apr 10 '14 at 15:38
  • 2
    @DanielSkowroński Thats _exactly_ what the empty constructor does, so your suggestion does absolutely nothing. The real solution is to avoid creating a new Random-instance all the time since it's costly. If you are worried about threading use the `ThreadStaticAttribute` on the field holding the random instance, and use a seed that doesn't depend solely on time, like `Guid.NewGuid().GetHashCode()`, or even a simple counter added to the mix `static int i;` and `new Random(Interlocked.Decrement(ref i) * Environment.TickCount)`. --> One Random per thread, all of them with different seeds. – AnorZaken Sep 26 '15 at 04:43
  • @GeneS Please, see [my answer](http://stackoverflow.com/a/41502836/1445568) – alex Jan 06 '17 at 09:48
  • 1
    This overflows for double.MinValue, double.MaxValue, as (double.MaxValue - double.MinValue) ~= 1.7e308 + 1.7e308 which is double the double.MaxValue – Piotr Falkowski Jun 15 '17 at 10:49
  • I'm finding due to rounding errors the result is actually exceeding my maximum. The range I chose was 0.5 to 1 and got 1.00754 – Zorgarath Sep 14 '18 at 02:44
  • 1
    This doesn't seem to work if the minimum and maximum values are `double.MinValue` and `double.MaxValue`. In that case, it returns `Infinity`. – Jonathan Wood Jul 19 '19 at 20:55
53

Johnny5 suggested creating an extension method. Here's a more complete code example showing how you could do this:

public static class RandomExtensions
{
    public static double NextDouble(
        this Random random,
        double minValue,
        double maxValue)
    {
        return random.NextDouble() * (maxValue - minValue) + minValue;
    }
}

Now you can call it as if it were a method on the Random class:

Random random = new Random();
double value = random.NextDouble(1.23, 5.34);

Note that you should not create lots of new Random objects in a loop because this will make it likely that you get the same value many times in a row. If you need lots of random numbers then create one instance of Random and re-use it.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
12

Watch out: if you're generating the random inside a loop like for example for(int i = 0; i < 10; i++), do not put the new Random() declaration inside the loop.

From MSDN:

The random number generation starts from a seed value. If the same seed is used repeatedly, the same series of numbers is generated. One way to produce different sequences is to make the seed value time-dependent, thereby producing a different series with each new instance of Random. By default, the parameterless constructor of the Random class uses the system clock to generate its seed value...

So based on this fact, do something as:

var random = new Random();

for(int d = 0; d < 7; d++)
{
    // Actual BOE
    boes.Add(new LogBOEViewModel()
    {
        LogDate = criteriaDate,
        BOEActual = GetRandomDouble(random, 100, 1000),
        BOEForecast = GetRandomDouble(random, 100, 1000)
    });
}

double GetRandomDouble(Random random, double min, double max)
{
     return min + (random.NextDouble() * (max - min));
}

Doing this way you have the guarantee you'll get different double values.

Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
11

I'm a bit late to the party but I needed to implement a general solution and it turned out that none of the solutions can satisfy my needs.

The accepted solution is good for small ranges; however, maximum - minimum can be infinity for big ranges. So a corrected version can be this version:

public static double NextDoubleLinear(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    double sample = random.NextDouble();
    return (maxValue * sample) + (minValue * (1d - sample));
}

This generates random numbers nicely even between double.MinValue and double.MaxValue. But this introduces another "problem", which is nicely presented in this post: if we use such big ranges the values might seem too "unnatural". For example, after generating 10,000 random doubles between 0 and double.MaxValue all of the values were between 2.9579E+304 and 1.7976E+308.

So I created also another version, which generates numbers on a logarithmic scale:

public static double NextDoubleLogarithmic(this Random random, double minValue, double maxValue)
{
    // TODO: some validation here...
    bool posAndNeg = minValue < 0d && maxValue > 0d;
    double minAbs = Math.Min(Math.Abs(minValue), Math.Abs(maxValue));
    double maxAbs = Math.Max(Math.Abs(minValue), Math.Abs(maxValue));

    int sign;
    if (!posAndNeg)
        sign = minValue < 0d ? -1 : 1;
    else
    {
        // if both negative and positive results are expected we select the sign based on the size of the ranges
        double sample = random.NextDouble();
        var rate = minAbs / maxAbs;
        var absMinValue = Math.Abs(minValue);
        bool isNeg = absMinValue <= maxValue ? rate / 2d > sample : rate / 2d < sample;
        sign = isNeg ? -1 : 1;

        // now adjusting the limits for 0..[selected range]
        minAbs = 0d;
        maxAbs = isNeg ? absMinValue : Math.Abs(maxValue);
    }

    // Possible double exponents are -1022..1023 but we don't generate too small exponents for big ranges because
    // that would cause too many almost zero results, which are much smaller than the original NextDouble values.
    double minExponent = minAbs == 0d ? -16d : Math.Log(minAbs, 2d);
    double maxExponent = Math.Log(maxAbs, 2d);
    if (minExponent == maxExponent)
        return minValue;

    // We decrease exponents only if the given range is already small. Even lower than -1022 is no problem, the result may be 0
    if (maxExponent < minExponent)
        minExponent = maxExponent - 4;

    double result = sign * Math.Pow(2d, NextDoubleLinear(random, minExponent, maxExponent));

    // protecting ourselves against inaccurate calculations; however, in practice result is always in range.
    return result < minValue ? minValue : (result > maxValue ? maxValue : result);
}

Some tests:

Here are the sorted results of generating 10,000 random double numbers between 0 and Double.MaxValue with both strategies. The results are displayed with using logarithmic scale:

0..Double.MaxValue

Though the linear random values seem to be wrong at first glance the statistics show that none of them are "better" than the other: even the linear strategy has an even distribution and the average difference between the values are pretty much the same with both strategies.

Playing with different ranges showed me that the linear strategy gets to be "sane" with range between 0 and ushort.MaxValue with a "reasonable" minimum value of 10.78294704 (for ulong range the minimum value was 3.03518E+15; int: 353341). These are the same results of both strategies displayed with different scales:

0..UInt16.MaxValue


Edit:

Recently I made my libraries open source, feel free to see the RandomExtensions.NextDouble method with the complete validation.

György Kőszeg
  • 17,093
  • 6
  • 37
  • 65
8

The simplest approach would simply generate a random number between 0 and the difference of the two numbers. Then add the smaller of the two numbers to the result.

Greg D
  • 43,259
  • 14
  • 84
  • 117
3

You could use code like this:

public double getRandomNumber(double minimum, double maximum) {
    return minimum + randomizer.nextDouble() * (maximum - minimum);
}
Malcolm
  • 41,014
  • 11
  • 68
  • 91
3

You could do this:

public class RandomNumbers : Random
{
    public RandomNumbers(int seed) : base(seed) { }

    public double NextDouble(double minimum, double maximum)
    {
        return base.NextDouble() * (maximum - minimum) + minimum;
    }
}
user490775
  • 31
  • 1
1

What if one of the values is negative? Wouldn't a better idea be:

double NextDouble(double min, double max)
{
       if (min >= max)
            throw new ArgumentOutOfRangeException();    
       return random.NextDouble() * (Math.Abs(max-min)) + min;
}
  • 6
    I think the `Math.Abs()` is redundant. Since you ensured that `min >= max`, then `max - min` must be a non-negative number anyway. – Brian Reischl Jun 18 '13 at 18:01
1

Use a static Random or the numbers tend to repeat in tight/fast loops due to the system clock seeding them.

public static class RandomNumbers
{
    private static Random random = new Random();
    //=-------------------------------------------------------------------
    // double between min and the max number
    public static double RandomDouble(int min, int max) 
    {
        return (random.NextDouble() * (max - min)) + min;
    }
    //=----------------------------------
    // double between 0 and the max number
    public static double RandomDouble(int max) 
    {
        return (random.NextDouble() * max);
    }
    //=-------------------------------------------------------------------
    // int between the min and the max number
    public static int RandomInt(int min, int max) 
    {   
        return random.Next(min, max + 1);
    }
    //=----------------------------------
    // int between 0 and the max number
    public static int RandomInt(int max) 
    {
        return random.Next(max + 1);
    }
    //=-------------------------------------------------------------------
 }

See also : https://learn.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.8

David C Fuchs
  • 357
  • 5
  • 11
0
Random random = new Random();

double NextDouble(double minimum, double maximum)
{  

    return random.NextDouble()*random.Next(minimum,maximum);

}
Leniel Maccaferri
  • 100,159
  • 46
  • 371
  • 480
0

If you need a random number in the range [double.MinValue; double.MaxValue]

// Because of:
double.MaxValue - double.MinValue == double.PositiveInfinity

// This will be equals to NaN or PositiveInfinity
random.NextDouble() * (double.MaxValue - double.MinValue)

Use instead:

public static class RandomExtensions
{
    public static double NextDoubleInMinMaxRange(this Random random)
    {
        var bytes = new byte[sizeof(double)];
        var value = default(double);
        while (true)
        {
            random.NextBytes(bytes);
            value = BitConverter.ToDouble(bytes, 0);
            if (!double.IsNaN(value) && !double.IsInfinity(value))
                return value;
        }
    }
}
alex
  • 5,661
  • 6
  • 33
  • 54
  • 2
    Good point, but this proposition results in skewed distribution like in second example here https://stackoverflow.com/a/3365388/3922292 – Piotr Falkowski Jun 17 '17 at 14:36
0

Random rand = new Random();

rand.Next(1,5)/10; //Means between 0,1 and 0,5

samedya
  • 1
  • 1
0

About generating the same random number if you call it in a loop a nifty solution is to declare the new Random() object outside of the loop as a global variable.

Notice that you have to declare your instance of the Random class outside of the GetRandomInt function if you are going to be running this in a loop.

“Why is this?” you ask.

Well, the Random class actually generates pseudo random numbers, with the “seed” for the randomizer being the system time. If your loop is sufficiently fast, the system clock time will not appear different to the randomizer and each new instance of the Random class would start off with the same seed and give you the same pseudo random number.

Source is here : http://www.whypad.com/posts/csharp-get-a-random-number-between-x-and-y/412/

Ajibola
  • 1,218
  • 16
  • 28
  • This is better suited as a comment, as it doesn't even attempt to answer OP's actual question. – arkon Aug 04 '16 at 01:01