Next Random Number

I was expecting (and thus using in places) the Random.Next Method (Int32, Int32) to return a random number between the lower and upper limits specified, both inclusive. However I was surprised to discover that actually "the range of return values includes minValue but not MaxValue."

As a result, doing something like this (in C#) will never return 5:

        Random rand = new Random();
        int num = rand.Next(1, 5);

Maybe this is obvious to some, but to me it wasn't and I was intuitively expecting both limits to be inclusive.

The logic behind having this behavior, I would guess, is the presumed familiarity of the C# developer with zero-based access. Since I found it confusing could it instead be a usability issue (we needed to run it by more developers to decide the correct behavior)?

Maybe MSDN documentation needs to start using bold red for words like "not" in such docs.

Comments (10)

  1. Me says:

    [0, n) is the expected and most useful behaviour for those with a mathematical background.

  2. Nat says:

    That API is made to be in line with the previous version of MS software such as:

    – Rnd function in VB will generate a random value >= 0 but < 1

    – Random.NextDouble in .NET where it returns a random value >= 0 but < 1

  3. JPDaigle says:

    It’s because that function is multiplying a random Double value in the range [0,1] (as far as I can tell) by the difference between maxValue and minValue, casting the result as an int, and finally adding minValue to this product.

    To end up with maxValue as the returned result, the sampled Double mentioned above would have to be *exactly* 1, because the cast to Integer doesn’t round to the closest int, it always rounds down. The probability of this occuring is therefore very small.

    I’m sure someone will correct me if I’m missing something important…

    The disassembly from Reflector looks like this:

    Public Overridable Function [Next](ByVal minValue As Integer, ByVal maxValue As Integer) As Integer

    If (minValue > maxValue) Then

    Throw New ArgumentOutOfRangeException("minValue", String.Format(Environment.GetResourceString("Argument_MinMaxValue"), "minValue", "maxValue"))

    End If

    Dim num1 As Integer = (maxValue – minValue)

    If (num1 < 0) Then

    Dim num2 As Long = (maxValue – minValue)

    Return CType((CType((Me.Sample * num2),Long) + minValue),Integer)

    End If

    Return (CType((Me.Sample * num1),Integer) + minValue)

    End Function

  4. damien morton says:

    its called a half-open interval, and it has all kinds of usefull properties:

  5. Luc Cluitmans says:

    I think the biggest problem here is not so much the actual semantics (which are nicely in line with ‘random’ functionality in other packages), but the naming of the ‘MaxValue’ parameter.

    Simply put, ‘MaxValue’ is not the maximum value, so give it a different name to indicate that. Next question is of course "what name then?". I have to admit that there is nothing that jumps to the foreground of my mind right now; maybe someone has a suggestion?

  6. Simon Smith says:

    I got caught by this too. I agree with Luc, and suggest that maxValue be changed to LessThan – that’s pretty obvious then!

  7. Great feedback!

    Seems like the Math background theory is probably the reason, but since not many "typical" developers would have a Math background, it seems worth considering for a revision. I did know about half-open (or half-closed) intervals and closed intervals but still expected it to be a closed rather than a half-open interval – based probably on the semantics of the parameter "MaxValue".

    I like Luc’s suggestion the best – a very simple and elegant solution, and I like it all the more because Intellisense (in VS) has gotten so good that many developers would learn about an API more through the explanation that shows up there rather than through the docs and help. This would solve the problem at the closest-to-the-developer level and is also probably the cheapest solution.

    BTW – the link I have in the post is to the single parameter version of Random.Next method, instead of the 2 parameter one below.

  8. mhalb1 says:

    Confusingly, even though I was expecting the behaviour as described in the documentation (i.e., MaxValue should not be returned) in my application it occasionally does and raises an exception when causing an array to go out of bounds. Altering my parameters to avoid the exception slows execution down as MaxValue is returned so infrequently and implies a distribution problem with the Random class.

    Anyone else seen this problem?

  9. ChrisN says:

    I propose the method description is renamed thus:

    Random.Next(int minValue, int maxValueWhichCannotBeReturnedAsAResultOfNextButCannotBeExceeded)

    or perhaps:

    Random.Next(int minValue, int beyondMaxValue)

    would be easier?

  10. Colwin says:

    Yup i got caught out by this too, after a bit of head scratching and good old Google i landed here, makes sense now though that it should be a half open interval.

Skip to main content