65

I need to generate a random integer between 1 and n (where n is a positive whole number) to use for a unit test. I don't need something overly complicated to ensure true randomness - just an old-fashioned random number.

How would I do that?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
brendan
  • 29,308
  • 20
  • 68
  • 109

12 Answers12

82

As has been pointed out many times, the suggestion to write code like this is problematic:

Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer
    Dim Generator As System.Random = New System.Random()
    Return Generator.Next(Min, Max)
End Function

The reason is that the constructor for the Random class provides a default seed based on the system's clock. On most systems, this has limited granularity -- somewhere in the vicinity of 20 ms. So if you write the following code, you're going to get the same number a bunch of times in a row:

Dim randoms(1000) As Integer
For i As Integer = 0 to randoms.Length - 1
    randoms(i) = GetRandom(1, 100)
Next

The following code addresses this issue:

Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer
    ' by making Generator static, we preserve the same instance '
    ' (i.e., do not create new instances with the same seed over and over) '
    ' between calls '
    Static Generator As System.Random = New System.Random()
    Return Generator.Next(Min, Max)
End Function

I threw together a simple program using both methods to generate 25 random integers between 1 and 100. Here's the output:

Non-static: 70 Static: 70
Non-static: 70 Static: 46
Non-static: 70 Static: 58
Non-static: 70 Static: 19
Non-static: 70 Static: 79
Non-static: 70 Static: 24
Non-static: 70 Static: 14
Non-static: 70 Static: 46
Non-static: 70 Static: 82
Non-static: 70 Static: 31
Non-static: 70 Static: 25
Non-static: 70 Static: 8
Non-static: 70 Static: 76
Non-static: 70 Static: 74
Non-static: 70 Static: 84
Non-static: 70 Static: 39
Non-static: 70 Static: 30
Non-static: 70 Static: 55
Non-static: 70 Static: 49
Non-static: 70 Static: 21
Non-static: 70 Static: 99
Non-static: 70 Static: 15
Non-static: 70 Static: 83
Non-static: 70 Static: 26
Non-static: 70 Static: 16
Non-static: 70 Static: 75
Dan Tao
  • 125,917
  • 54
  • 300
  • 447
  • 1
    i think this will never actually generate "100". it's between min and less than MaxValue actually (I think) – ChatGPT Apr 11 '12 at 13:29
  • 2
    @maxhodges: Yeah, I think you're right. There's an unfortunate ambiguity in the word "between"; I don't know if the OP cares whether 100 is included or not. I didn't, personally; my answer was only intended to illustrate sharing a `Random` object among multiple function calls using the `Static` keyword. – Dan Tao Apr 11 '12 at 13:56
  • I have found that I needed to reference this code more than once. Thank you! – MonkeyDoug Jun 30 '13 at 17:53
  • i would +1 you for the Static insight, but the code is buggy. but kudos for that static insight! and i'd -1 you for a buggy answer. but they even out. – Shawn Kovac Jan 30 '14 at 15:24
  • 4
    if you want a bug, then use this code. MS made their Next() method rather odd. the Min parameter is the inclusive minimum as one would expect, but the Max parameter is the exclusive minimum as one would NOT expect. in other words, if you pass min=1 and max=5 then your random numbers would be any of 1, 2, 3, or 4, but it would never include 5. – Shawn Kovac Jan 30 '14 at 15:24
  • 4
    @ShawnKovac: I can appreciate that it can be surprising. But calling it "buggy" is a little overkill, in my opinion; it just wasn't the behavior *you* were expecting. The truth is that most random number implementations (that I know of) work this way: inclusive lower bound, exclusive upper bound. It can be convenient in a lot of common use cases, like selecting a random item from an array (where you select the item between `0` and `array.length`). – Dan Tao Jan 30 '14 at 15:37
  • For example: [`Random.nextInt`](http://docs.oracle.com/javase/7/docs/api/java/util/Random.html#nextInt(int)) in Java, [`Math.random`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random) in JavaScript, [`rand`](http://www.ruby-doc.org/core-2.1.0/Random.html#method-i-rand) in Ruby, etc. – Dan Tao Jan 30 '14 at 15:39
  • 1
    thanks Dan. i appreciate that feedback. it is awkward at best, and then i see programmers who think 'minimum' and 'maximum' have a consistent similarity as being inclusive and exclusive... yes, as i would. but this is human. so many 'quirks' in programming is why programming is as tricky as it is. and we just need to write better code. i appreciate your feedback tho. thanks. – Shawn Kovac Jan 30 '14 at 16:37
  • i believe what i would call not buggy nor quirky, but even quality code is if the variables were simply named to reflect *clearly* what they are: incMin and excMax would be feasible short names. :) and maybe a comment that incMin = inclusive minimum & excMax = exclusive maximum. – Shawn Kovac Jan 30 '14 at 16:37
  • @dantao: i quite appreciate your feedback. thanks for opening my mind a bit more (at least as much as i allow myself to see it another way). ;) I've named my variables in my 'fixed code' so other programmers who may see my code later would not be confused if they expected this 'quirky' behavior, (which to me, i still feel it is buggy because it is not a consistent use of both parameters being either inclusive or exclusive). my method uses inclusive limits for both parameters, which also allows the maximum, full range of an int as the result, which is how i feel it should be coded. – Shawn Kovac Jan 30 '14 at 16:47
  • @ShawnKovac: You're not alone. Python's [`random.randint`](http://docs.python.org/2/library/random.html#random.randint), for example, is inclusive on both ends. And I agree with you that the variable names `min` and `max` should probably be more explicit (in fact you can see I mention the ambiguity in my earlier comment from April 2012!). I guess one of the trickier questions when designing an interface is this: do you try to make it intuitive "in a vacuum", or do you draw on developers' expectations from what has come before? – Dan Tao Jan 30 '14 at 16:52
  • @ShawnKovac: 0-based array indexing is a perfect example. It's arguably not "intuitive" (for some, at least at first), but it's so widespread that now if you were to create a new language that used 1-based indexing you'd actually *surprise* a lot of devs. So the unintuitive can become intuitive based on prior experience. My feeling with `Random.Next` in .NET is that it's somewhere in a gray area. Plenty of devs (like you) surely find it surprising, but I would guess that there are also quite a few who expect exactly the behavior it has. – Dan Tao Jan 30 '14 at 16:54
  • yes, i understand the catering to reverse use. it's funny i was thinking about VB's max index when declaring an array is counter-intuitive due to the 'expected' C-style declaration which is so common. but you are right, the bigger picture is the whole 0-indexing issue. you are very right. now we are used to it and it'd be more awkward to use 1-based indexing... now that i'm used to it. which i believe is your point exactly. thanks for those points and sharing your wisdom! VB's Instr() method is a good example too with 1-based indexing. well, i guess one thing for sure is change with time. :) – Shawn Kovac Jan 30 '14 at 17:01
  • I modified the function as follows: Public Function GetRandom(ByVal Min As Integer, ByVal Max As Integer) As Integer ' by making Generator static, we preserve the same instance ' ' (i.e., do not create new instances with the same seed over and over) ' ' between calls ' Static Generator As System.Random = New System.Random() Dim Result as Integer = Generator.Next(Min, Max) if Result = Max then result -= 1 End Function I then pass 1 more than the max I want (e.g. if I want max of 255, I pass 256 as max). – SEFL Nov 24 '16 at 17:40
  • You can always add the numbers to a list then check the list with contains and only add the number if it is not already there. 5 out of a possible 10 would be pretty quick even if there were a few duplicates generated along the way. Use list to array if it really has to be in an array. – Robert Quinn May 06 '18 at 15:19
  • Worked perfectly the 1st time. Thank you. – pianocomposer Feb 16 '21 at 19:35
66

To get a random integer value between 1 and N (inclusive) you can use the following.

CInt(Math.Ceiling(Rnd() * n)) + 1
brendan
  • 29,308
  • 20
  • 68
  • 109
Kibbee
  • 65,369
  • 27
  • 142
  • 182
  • 7
    *"between 1 and N (inclusive)"* wrong, will return a value between `0` and `N`. `Math.Ceiling(0)` is `0`. – Qtax Jul 18 '12 at 21:09
  • 5
    Rnd() can return 0. If this happens then even when n > 0, the result would be 0. Thus this would give a very nasty bug especially because it is so rare. if you want buggy code, then use this. MS documentation reads: "The Rnd function returns a value less than 1, but greater than or equal to zero." http://msdn.microsoft.com/en-us/library/f7s023d2(v=vs.90).aspx – Shawn Kovac Jan 30 '14 at 15:10
  • 8
    Tried this out as is and ran into instance of 12 when using n=11. Not inclusive. MSDN has better example: randomValue = CInt(Math.Floor((upperbound - lowerbound + 1) * Rnd())) + lowerbound – eric1825 Dec 19 '14 at 18:27
  • `Rnd()` is part of [0;1[. If you want a number part of ]0;1], then you can use `1-Rnd()`. – Ama May 17 '19 at 17:31
37

Use System.Random:

Dim MyMin As Integer = 1, MyMax As Integer = 5, My1stRandomNumber As Integer, My2ndRandomNumber As Integer

' Create a random number generator
Dim Generator As System.Random = New System.Random()

' Get a random number >= MyMin and <= MyMax
My1stRandomNumber = Generator.Next(MyMin, MyMax + 1) ' Note: Next function returns numbers _less than_ max, so pass in max + 1 to include max as a possible value

' Get another random number (don't create a new generator, use the same one)
My2ndRandomNumber = Generator.Next(MyMin, MyMax + 1)
Joseph Sturtevant
  • 13,194
  • 12
  • 76
  • 90
  • 7
    Looks simpler with return New Random().Next(minValue,maxValue) – Ignacio Soler Garcia Feb 02 '10 at 10:25
  • 2
    True. However, if the user wanted a sequence of random numbers (rather than just one), they would want to hold onto the Random reference. – Joseph Sturtevant Feb 03 '10 at 00:01
  • 1
    Change `Dim Generator` to `Static Generator` and you've got an instance you can hold onto (not a thread-safe one, but that's not going to matter in most realistic scenarios). – Dan Tao Apr 20 '10 at 18:50
  • 1
    it looks simpler, but this code is plain wrong. if you want a bug, then use this code. MS made their Next() method rather odd. the Min parameter is the inclusive minimum as one would expect, but the Max parameter is the *exclusive* minimum as one would NOT expect. in other words, if you pass min=1 and max=5 then your random numbers would be any of 1, 2, 3, or 4, but it would never include 5. – Shawn Kovac Jan 30 '14 at 15:15
  • @ShawnKovac - Good catch. I hadn't noticed the inclusive\exclusive mismatch between Random.Next's min & max parameters. Code sample updated. – Joseph Sturtevant Feb 01 '14 at 19:27
5

Microsoft Example Rnd Function

https://msdn.microsoft.com/en-us/library/f7s023d2%28v=vs.90%29.aspx

1- Initialize the random-number generator.

Randomize()

2 - Generate random value between 1 and 6.

Dim value As Integer = CInt(Int((6 * Rnd()) + 1))
Wais
  • 1,739
  • 1
  • 13
  • 13
4
Public Function RandomNumber(ByVal n As Integer) As Integer
    'initialize random number generator
    Dim r As New Random(System.DateTime.Now.Millisecond)
    Return r.Next(1, n)
End Function
Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
  • 2
    if you want bugs, then use this code. MS made their Next() method rather odd. the Min parameter is the inclusive minimum as one would expect, but the Max parameter is the exclusive maximum as one would NOT expect. in other words, if you pass min=1 and max=5 then your random numbers would be any of 1, 2, 3, or 4, but it would never include 5. – Shawn Kovac Jan 30 '14 at 16:31
  • 5
    @ShawnKovac That's how most random number generators are implemented. – Bill the Lizard Jan 30 '14 at 17:53
4

All the answers so far have problems or bugs (plural, not just one). I will explain. But first I want to compliment Dan Tao's insight to use a static variable to remember the Generator variable so calling it multiple times will not repeat the same # over and over, plus he gave a very nice explanation. But his code suffered the same flaw that most others have, as i explain now.

MS made their Next() method rather odd. the Min parameter is the inclusive minimum as one would expect, but the Max parameter is the exclusive maximum as one would NOT expect. in other words, if you pass min=1 and max=5 then your random numbers would be any of 1, 2, 3, or 4, but it would never include 5. This is the first of two potential bugs in all code that uses Microsoft's Random.Next() method.

For a simple answer (but still with other possible but rare problems) then you'd need to use:

Private Function GenRandomInt(min As Int32, max As Int32) As Int32
    Static staticRandomGenerator As New System.Random
    Return staticRandomGenerator.Next(min, max + 1)
End Function

(I like to use Int32 rather than Integer because it makes it more clear how big the int is, plus it is shorter to type, but suit yourself.)

I see two potential problems with this method, but it will be suitable (and correct) for most uses. So if you want a simple solution, i believe this is correct.

The only 2 problems i see with this function is: 1: when Max = Int32.MaxValue so adding 1 creates a numeric overflow. altho, this would be rare, it is still a possibility. 2: when min > max + 1. when min = 10 and max = 5 then the Next function throws an error. this may be what you want. but it may not be either. or consider when min = 5 and max = 4. by adding 1, 5 is passed to the Next method, but it does not throw an error, when it really is an error, but Microsoft .NET code that i tested returns 5. so it really is not an 'exclusive' max when the max = the min. but when max < min for the Random.Next() function, then it throws an ArgumentOutOfRangeException. so Microsoft's implementation is really inconsistent and buggy too in this regard.

you may want to simply swap the numbers when min > max so no error is thrown, but it totally depends on what is desired. if you want an error on invalid values, then it is probably better to also throw the error when Microsoft's exclusive maximum (max + 1) in our code equals minimum, where MS fails to error in this case.

handling a work-around for when max = Int32.MaxValue is a little inconvenient, but i expect to post a thorough function which handles both these situations. and if you want different behavior than how i coded it, suit yourself. but be aware of these 2 issues.

Happy coding!

Edit: So i needed a random integer generator, and i decided to code it 'right'. So if anyone wants the full functionality, here's one that actually works. (But it doesn't win the simplest prize with only 2 lines of code. But it's not really complex either.)

''' <summary>
''' Generates a random Integer with any (inclusive) minimum or (inclusive) maximum values, with full range of Int32 values.
''' </summary>
''' <param name="inMin">Inclusive Minimum value. Lowest possible return value.</param>
''' <param name="inMax">Inclusive Maximum value. Highest possible return value.</param>
''' <returns></returns>
''' <remarks></remarks>
Private Function GenRandomInt(inMin As Int32, inMax As Int32) As Int32
    Static staticRandomGenerator As New System.Random
    If inMin > inMax Then Dim t = inMin : inMin = inMax : inMax = t
    If inMax < Int32.MaxValue Then Return staticRandomGenerator.Next(inMin, inMax + 1)
    ' now max = Int32.MaxValue, so we need to work around Microsoft's quirk of an exclusive max parameter.
    If inMin > Int32.MinValue Then Return staticRandomGenerator.Next(inMin - 1, inMax) + 1 ' okay, this was the easy one.
    ' now min and max give full range of integer, but Random.Next() does not give us an option for the full range of integer.
    ' so we need to use Random.NextBytes() to give us 4 random bytes, then convert that to our random int.
    Dim bytes(3) As Byte ' 4 bytes, 0 to 3
    staticRandomGenerator.NextBytes(bytes) ' 4 random bytes
    Return BitConverter.ToInt32(bytes, 0) ' return bytes converted to a random Int32
End Function
Shawn Kovac
  • 1,425
  • 15
  • 17
  • 2
    Complete nonsense. As Bill said, the behaviour of `Next()` is entirely normal, not "rather odd". – Lightness Races in Orbit Sep 17 '15 at 14:39
  • 1
    To be fair, as "normal" as it might be for built-in functions of various programming languages, it's actually rather odd for the rest of the world. When's the last time you heard someone say 1D6 gives you a number between 1 and 7? For anyone who hasn't carefully read the language's documentation and isn't particularly familiar with the normally odd behavior of RNG functions, they could be in for a surprise and not really know what happened. – MichaelS Dec 28 '15 at 07:22
  • @MichaelS, you lost me with '1D6' giving a # between 1 & 7. i don't understand your 'D'. But also in regards 2 how Microsoft's Random.Next(min, max) works, the program provides 1 & 7 and the method returns a # within the range of 1 & 6. So i think u were slightly off of the exact accuracy of your analogy (unless you were referring to some other nonsensical behavior. But if you were intending to refer to Microsoft's, i just say that your little mix-up is perfectly *normal* because what MS did makes no logical sense (other than what others have pointed out: that it's become the new 'norm'). – Shawn Kovac Dec 29 '15 at 13:09
  • And i am simply vocalizing a little bit of logic that it is better logically to use inclusive min and inclusive max for consistency and to reject the quasi-'norm' that has began. That's all. :) – Shawn Kovac Dec 29 '15 at 13:11
  • 1D6 means roll one six-sided die -- the kind used in many board games or a tabletop RPG. The numbers range from 1 to 6, inclusive, and people would say "1 to 6", not "1 to 7" and assume you know 7 isn't included. You could use similar analogies from many other aspects of life. If I say a baseball league is for children between 12 and 14, I'm including both 12 and 14. Etc. I can't think of a practical example of excluding the upper bound of a range outside a math class. – MichaelS Jan 04 '16 at 04:57
  • Okay, @MichaelS, now that i understand your post, i see that you and i completely agree. You just expressed the same concept in yet another way. Nice point. :) Thanks for the clarification. – Shawn Kovac Jan 11 '16 at 17:55
2

You should create a pseudo-random number generator only once:

Dim Generator As System.Random = New System.Random()

Then, if an integer suffices for your needs, you can use:

Public Function GetRandom(myGenerator As System.Random, ByVal Min As Integer, ByVal Max As Integer) As Integer
'min is inclusive, max is exclusive (dah!)
Return myGenerator.Next(Min, Max + 1)
End Function

as many times as you like. Using the wrapper function is justified only because the maximum value is exclusive - I know that the random numbers work this way but the definition of .Next is confusing.

Creating a generator every time you need a number is in my opinion wrong; the pseudo-random numbers do not work this way.

First, you get the problem with initialization which has been discussed in the other replies. If you initialize once, you do not have this problem.

Second, I am not at all certain that you get a valid sequence of random numbers; rather, you get a collection of the first number of multiple different sequences which are seeded automatically based on computer time. I am not certain that these numbers will pass the tests that confirm the randomness of the sequence.

achar
  • 41
  • 4
1

If you are using Joseph's answer which is a great answer, and you run these back to back like this:

dim i = GetRandom(1, 1715)
dim o = GetRandom(1, 1715)

Then the result could come back the same over and over because it processes the call so quickly. This may not have been an issue in '08, but since the processors are much faster today, the function doesn't allow the system clock enough time to change prior to making the second call.

Since the System.Random() function is based on the system clock, we need to allow enough time for it to change prior to the next call. One way of accomplishing this is to pause the current thread for 1 millisecond. See example below:

Public Function GetRandom(ByVal min as Integer, ByVal max as Integer) as Integer
    Static staticRandomGenerator As New System.Random
    max += 1
    Return staticRandomGenerator.Next(If(min > max, max, min), If(min > max, min, max))
End Function
Rogala
  • 2,679
  • 25
  • 27
  • 2
    if you want a bug, then use this code. MS made their Next() method rather odd. the Min parameter is the inclusive minimum as one would expect, but the Max parameter is the exclusive minimum as one would NOT expect. in other words, if you pass min=1 and max=5 then your random numbers would be any of 1, 2, 3, or 4, but it would never include 5. – Shawn Kovac Jan 30 '14 at 15:26
  • @ShawnKovac Thank you for enlightening me about the .Next function not returning the Max number and the use of the static system.random object (although the name Min and Max are probably no longer appropriate since this is now just a range: A to B). I did a test, and the performance of the two are equal. Also, I use integer instead of int32 because it is currently bound to int32 (making them almost the same) and since I do a lot of work in SQL, I like the syntax and don't mind typing the 'e' before my 'tab.' (To each their own though.) ~Cheers – Rogala Mar 21 '14 at 19:16
  • thanks for caring to correct your code. you are well beyond many other people in that. Yes, Int32 and Integer produces the same effect, as far as i know, exactly the same. Except to me, Int32 is more clear, for people who don't know what size of Integer an 'Ingeger' is. That's the biggest reason i use Int32. But i understand it's totally a preference thing. – Shawn Kovac Mar 27 '14 at 16:06
  • I also like the shorter Int32 alias, and yes, with intellisence the typing is about equal. But i like more compact reading too. But when i code C#, i still like to use the more specific Int32 rather than its even shorter 'int' in case newbies are looking at my code, for other people's clarity sake. But to each his own. :) – Shawn Kovac Mar 27 '14 at 16:08
  • I just want to point out that your code will either bug out or throw an error if your max = Integer.MaxValue. Of course, this usually won't matter, but if you wanted to eliminate that potential issue, you can see my answer where i provided a solution to give the full range of random Int, if the user wanted to include Integer.MaxValue. Unfortunately, Microsoft just didn't make it easy to have very robust code for this when they implemented what i call an extremely quirky random function. Truly robust code is hard to come by. :( – Shawn Kovac Mar 27 '14 at 16:11
0
Dim rnd As Random = New Random
rnd.Next(n)
Binny
  • 328
  • 5
  • 21
0

Just for reference, VB NET Fuction definition for RND and RANDOMIZE (which should give the same results of BASIC (1980 years) and all versions after is:

Public NotInheritable Class VBMath
    ' Methods
    Private Shared Function GetTimer() As Single
        Dim now As DateTime = DateTime.Now
        Return CSng((((((60 * now.Hour) + now.Minute) * 60) + now.Second) + (CDbl(now.Millisecond) / 1000)))
    End Function

    Public Shared Sub Randomize()
        Dim timer As Single = VBMath.GetTimer
        Dim projectData As ProjectData = ProjectData.GetProjectData
        Dim rndSeed As Integer = projectData.m_rndSeed
        Dim num3 As Integer = BitConverter.ToInt32(BitConverter.GetBytes(timer), 0)
        num3 = (((num3 And &HFFFF) Xor (num3 >> &H10)) << 8)
        rndSeed = ((rndSeed And -16776961) Or num3)
        projectData.m_rndSeed = rndSeed
    End Sub

    Public Shared Sub Randomize(ByVal Number As Double)
        Dim num2 As Integer
        Dim projectData As ProjectData = ProjectData.GetProjectData
        Dim rndSeed As Integer = projectData.m_rndSeed
        If BitConverter.IsLittleEndian Then
            num2 = BitConverter.ToInt32(BitConverter.GetBytes(Number), 4)
        Else
            num2 = BitConverter.ToInt32(BitConverter.GetBytes(Number), 0)
        End If
        num2 = (((num2 And &HFFFF) Xor (num2 >> &H10)) << 8)
        rndSeed = ((rndSeed And -16776961) Or num2)
        projectData.m_rndSeed = rndSeed
    End Sub

    Public Shared Function Rnd() As Single
        Return VBMath.Rnd(1!)
    End Function

    Public Shared Function Rnd(ByVal Number As Single) As Single
        Dim projectData As ProjectData = ProjectData.GetProjectData
        Dim rndSeed As Integer = projectData.m_rndSeed
        If (Number <> 0) Then
            If (Number < 0) Then
                Dim num1 As UInt64 = (BitConverter.ToInt32(BitConverter.GetBytes(Number), 0) And &HFFFFFFFF)
                rndSeed = CInt(((num1 + (num1 >> &H18)) And CULng(&HFFFFFF)))
            End If
            rndSeed = CInt((((rndSeed * &H43FD43FD) + &HC39EC3) And &HFFFFFF))
        End If
        projectData.m_rndSeed = rndSeed
        Return (CSng(rndSeed) / 1.677722E+07!)
    End Function

End Class

While the Random CLASS is:

Public Class Random
    ' Methods
    <__DynamicallyInvokable> _
    Public Sub New()
        Me.New(Environment.TickCount)
    End Sub

    <__DynamicallyInvokable> _
    Public Sub New(ByVal Seed As Integer)
        Me.SeedArray = New Integer(&H38  - 1) {}
        Dim num4 As Integer = If((Seed = -2147483648), &H7FFFFFFF, Math.Abs(Seed))
        Dim num2 As Integer = (&H9A4EC86 - num4)
        Me.SeedArray(&H37) = num2
        Dim num3 As Integer = 1
        Dim i As Integer
        For i = 1 To &H37 - 1
            Dim index As Integer = ((&H15 * i) Mod &H37)
            Me.SeedArray(index) = num3
            num3 = (num2 - num3)
            If (num3 < 0) Then
                num3 = (num3 + &H7FFFFFFF)
            End If
            num2 = Me.SeedArray(index)
        Next i
        Dim j As Integer
        For j = 1 To 5 - 1
            Dim k As Integer
            For k = 1 To &H38 - 1
                Me.SeedArray(k) = (Me.SeedArray(k) - Me.SeedArray((1 + ((k + 30) Mod &H37))))
                If (Me.SeedArray(k) < 0) Then
                    Me.SeedArray(k) = (Me.SeedArray(k) + &H7FFFFFFF)
                End If
            Next k
        Next j
        Me.inext = 0
        Me.inextp = &H15
        Seed = 1
    End Sub

    Private Function GetSampleForLargeRange() As Double
        Dim num As Integer = Me.InternalSample
        If ((Me.InternalSample Mod 2) = 0) Then
            num = -num
        End If
        Dim num2 As Double = num
        num2 = (num2 + 2147483646)
        Return (num2 / 4294967293)
    End Function

    Private Function InternalSample() As Integer
        Dim inext As Integer = Me.inext
        Dim inextp As Integer = Me.inextp
        If (++inext >= &H38) Then
            inext = 1
        End If
        If (++inextp >= &H38) Then
            inextp = 1
        End If
        Dim num As Integer = (Me.SeedArray(inext) - Me.SeedArray(inextp))
        If (num = &H7FFFFFFF) Then
            num -= 1
        End If
        If (num < 0) Then
            num = (num + &H7FFFFFFF)
        End If
        Me.SeedArray(inext) = num
        Me.inext = inext
        Me.inextp = inextp
        Return num
    End Function

    <__DynamicallyInvokable> _
    Public Overridable Function [Next]() As Integer
        Return Me.InternalSample
    End Function

    <__DynamicallyInvokable> _
    Public Overridable Function [Next](ByVal maxValue As Integer) As Integer
        If (maxValue < 0) Then
            Dim values As Object() = New Object() { "maxValue" }
            Throw New ArgumentOutOfRangeException("maxValue", Environment.GetResourceString("ArgumentOutOfRange_MustBePositive", values))
        End If
        Return CInt((Me.Sample * maxValue))
    End Function

    <__DynamicallyInvokable> _
    Public Overridable Function [Next](ByVal minValue As Integer, ByVal maxValue As Integer) As Integer
        If (minValue > maxValue) Then
            Dim values As Object() = New Object() { "minValue", "maxValue" }
            Throw New ArgumentOutOfRangeException("minValue", Environment.GetResourceString("Argument_MinMaxValue", values))
        End If
        Dim num As Long = (maxValue - minValue)
        If (num <= &H7FFFFFFF) Then
            Return (CInt((Me.Sample * num)) + minValue)
        End If
        Return (CInt(CLng((Me.GetSampleForLargeRange * num))) + minValue)
    End Function

    <__DynamicallyInvokable> _
    Public Overridable Sub NextBytes(ByVal buffer As Byte())
        If (buffer Is Nothing) Then
            Throw New ArgumentNullException("buffer")
        End If
        Dim i As Integer
        For i = 0 To buffer.Length - 1
            buffer(i) = CByte((Me.InternalSample Mod &H100))
        Next i
    End Sub

    <__DynamicallyInvokable> _
    Public Overridable Function NextDouble() As Double
        Return Me.Sample
    End Function

    <__DynamicallyInvokable> _
    Protected Overridable Function Sample() As Double
        Return (Me.InternalSample * 4.6566128752457969E-10)
    End Function


    ' Fields
    Private inext As Integer
    Private inextp As Integer
    Private Const MBIG As Integer = &H7FFFFFFF
    Private Const MSEED As Integer = &H9A4EC86
    Private Const MZ As Integer = 0
    Private SeedArray As Integer()
End Class
Zibri
  • 9,096
  • 3
  • 52
  • 44
0

I see a lot of answers of users that are not satisfied with using System.Random.

Despite the fact that I personally would still use System.Random, I was thinking about a way to use a GUID as the base for a random value. A GUID can be converted to a byte array using its ToByteArray method, and the resulting byte array can be converted to a numeric value using a BitConverter.

'Function for reuse (min is inclusive and max is exclusive)
Function GetRandom(min As Integer, max As Integer) As Integer
    Return BitConverter.ToUInt64(Guid.NewGuid.ToByteArray) Mod (max - min) + min
End Function
'one-liner specific for your purpose (n is exclusive)
BitConverter.ToUInt64(Guid.NewGuid.ToByteArray) Mod (n - 1) + 1

Note that this is just a little thought experiment. I haven't tested the performance, nor have I investigated the actual "randomness" of the results. But for your purpose, it might just do the job.

The accepted answer uses the Microsoft.VisualBasic.VBMath.Rnd method, which indeed offers a simple and attractive oneliner, but I personally would avoid writing new code that uses the Microsoft.VisualBasic namespace.

Bart Hofland
  • 3,700
  • 1
  • 13
  • 22
-5
Function xrand() As Long
        Dim r1 As Long = Now.Day & Now.Month & Now.Year & Now.Hour & Now.Minute & Now.Second & Now.Millisecond
        Dim RAND As Long = Math.Max(r1, r1 * 2)
        Return RAND
End Function

[BBOYSE] This its the best way, from scratch :P

patmortech
  • 10,139
  • 5
  • 38
  • 50
Sergiu
  • 15
  • 2
  • 3
    this is horrible. it's not random at all. it's only a precomputed number based on the time. this would not exhibit any properties of a random number. plus it does not answer the question. the question was not how to generate any random number but one between 1 and a given value. – Shawn Kovac Jan 30 '14 at 15:33