Random number between two numbers without overflowing

486 views c#
4

I realize this question has been asked countless times, but it seems that every answer does not take into account overflows.

The suggested method is as follows

public static double BoundedNext( double min, double max )
{
  var random = new Random( Guid.NewGuid().GetHashCode() );
  return ( random.NextDouble() * ( max - min ) ) + min;
}

In just about every single case, this works as it should. However, it does not properly handle cases where an overflow occurs, such as BoundedNext(Double.MinValue, Double.MaxValue). The issue becomes even trickier in languages like C#, where an overflowed double equates to -/+ infinity.

The simple solution would be to just use a larger type, but I would like a solution that is able to produce a random number between two numbers, for each explicit type, that can handle overflow cases.

answered question

1 Answer

11

There is a nice solution for this, as your question is well in place, I will share it with you, as I always keep it in my backlog files just in case:

  static Random random = new Random();

    // Note, max is exclusive here!
    public static List<int> GenerateRandom(int count, double min, double max)
    {

        if (max <= min || count < 0 || 
                // max - min > 0 required to avoid overflow
                (count > max - min && max - min > 0))
        {
            // need to use 64-bit to support big ranges (negative min, positive max)
            throw new ArgumentOutOfRangeException("Range " + min + " to " + max + 
                    " (" + ((Double)max - (Double)min) + " values), or count " + count + " is illegal");
        }

        // generate count random values.
        HashSet<int> candidates = new HashSet<int>();

        // start count values before max, and end at max
        for (double top = max - count; top < max; top++)
        {
            // May strike a duplicate.
            // Need to add +1 to make inclusive generator
            // +1 is safe even for MaxVal max value because top < max
            if (!candidates.Add(random.Next(min, top + 1))) {
                // collision, add inclusive max.
                // which could not possibly have been added before.
                candidates.Add(top);
            }
        }

        // load them in to a list, to sort
        List<int> result = candidates.ToList();

        // shuffle the results because HashSet has messed
        // with the order, and the algorithm does not produce
        // random-ordered results (e.g. max-1 will never be the first value)
        for (int i = result.Count - 1; i > 0; i--)
        {  
            int k = random.Next(i + 1);  
            int tmp = result[k];  
            result[k] = result[i];  
            result[i] = tmp;  
        }  
        return result;
    }

    public static List<int> GenerateRandom(int count)
    {
        return GenerateRandom(count, 0, Double.MaxValue);
    }

This solution was written in Int64 so I tried to adopt it for double as much as I could for you. Take it and revise it for your needs.

  • Please note the comment suggesting what is required to avoid overflow

posted this

Have an answer?

JD

Please login first before posting an answer.