Вопрос

Мне нужно сгенерировать случайное целое число от 1 до n (где n - положительное целое число) для использования в модульном тестировании.Мне не нужно что-то чрезмерно сложное, чтобы обеспечить истинную случайность - просто старомодное случайное число.

Как бы я это сделал?

Это было полезно?

Решение

Чтобы получить случайное целое значение от 1 до N (включительно), вы можете использовать следующее.

CInt(Math.Ceiling(Rnd() * n)) + 1

Другие советы

Как уже много раз указывалось, предложение написать подобный код проблематично:

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

Причина в том, что конструктор для Random класс предоставляет начальное значение по умолчанию, основанное на системных часах.В большинстве систем это имеет ограниченную детализацию - где-то около 20 мс.Итак, если вы напишете следующий код, вы получите одно и то же число несколько раз подряд:

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

Следующий код устраняет эту проблему:

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

Я собрал простую программу, использующую оба метода для генерации 25 случайных целых чисел от 1 до 100.Вот результат:

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

Использование Система.Случайный:

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)

Все ответы на данный момент содержат проблемы или баги (во множественном числе, а не только в одном).Я сейчас объясню.Но сначала я хочу похвалить идею Дэна Тао использовать статическую переменную для запоминания переменной генератора, чтобы, вызывая ее несколько раз, не повторять один и тот же # снова и снова, плюс он дал очень хорошее объяснение.Но его код страдал тем же недостатком, что и большинство других, как я сейчас объясню.

MS сделала свой метод Next() довольно странным.параметр Min - это инклюзивный минимум, как и следовало ожидать, но параметр Max - это Эксклюзив максимум, которого НЕЛЬЗЯ было бы ожидать.другими словами, если вы передадите min = 1 и max = 5, то вашими случайными числами будут любые из 1, 2, 3 или 4, но они никогда не будут включать 5.Это первая из двух потенциальных ошибок во всем коде, использующем метод Microsoft Random.Next().

Для простой ответ (но все еще с другими возможными, но редкими проблемами), тогда вам нужно будет использовать:

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

(Мне нравится использовать Int32 вместо того , чтобы Integer потому что это делает более понятным, насколько велик int, плюс его короче вводить, но делайте это как хотите.)

Я вижу две потенциальные проблемы с этим методом, но он будет подходящим (и правильным) для большинства применений.Так что, если вы хотите простой решение, я считаю, это правильное.

Единственные 2 проблемы, которые я вижу с этой функцией, это:1:когда Max = Int32.MaxValue, таким образом, добавление 1 создает числовое переполнение.хотя это было бы редкостью, это все же возможно.2:когда min > max + 1.когда min = 10 и max = 5, следующая функция выдает ошибку.возможно, это то, чего вы хотите.но это может быть и не то, и не другое.или рассмотрим, когда min = 5 и max = 4.при добавлении 1, 5 передается следующему методу, но он выдает не ошибку, когда это действительно ошибка, а Microsoft .ЧИСТЫЙ код, который я тестировал, возвращает 5.так что это действительно не "эксклюзивный" максимум, когда max = min.но когда макс < min для функции Random.Next(), затем она выдает исключение ArgumentOutOfRangeException.таким образом, реализация Microsoft действительно непоследовательна и глючит в этом отношении.

возможно, вы захотите просто поменять местами числа, когда min > max, чтобы ошибка не выдавалась, но это полностью зависит от того, что требуется.если вам нужна ошибка при недопустимых значениях, то, вероятно, лучше также выдавать ошибку, когда исключительный максимум Microsoft (max + 1) в нашем коде равен минимуму, где MS не выдает ошибку в этом случае.

обработка обходного пути для случая, когда max = Int32.MaxValue немного неудобна, но я ожидаю опубликовать подробную функцию, которая обрабатывает обе эти ситуации.и если вы хотите, чтобы поведение отличалось от того, как я его закодировал, поступайте как хотите.но имейте в виду эти 2 проблемы.

Счастливого кодирования!

Редактировать:Итак, мне нужен был генератор случайных целых чисел, и я решил закодировать его "правильно".Так что, если кому-то нужна полная функциональность, вот та, которая действительно работает.(Но он не выигрывает самый простой приз, имея всего 2 строки кода.Но на самом деле это тоже не так уж сложно.)

''' <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
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

Пример Microsoft Функция Rnd

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

1- Инициализируйте генератор случайных чисел.

Randomize()

2 - Сгенерировать случайное значение от 1 до 6.

Dim value As Integer = CInt(Int((6 * Rnd()) + 1))

Если вы используете ответ Джозефа, который является отличным ответом, и вы запускаете их последовательно, вот так:

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

Тогда результат может возвращаться к одному и тому же снова и снова, потому что он обрабатывает вызов очень быстро.Возможно, в '08 это не было проблемой, но поскольку сегодня процессоры намного быстрее, функция не дает системным часам достаточно времени для изменения перед выполнением второго вызова.

Поскольку функция System.Random() основана на системных часах, нам нужно предоставить достаточно времени для ее изменения до следующего вызова.Один из способов добиться этого - приостановить текущий поток на 1 миллисекунду.Смотрите пример ниже:

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

Вы должны создать генератор псевдослучайных чисел только один раз:

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

Затем, если для ваших нужд достаточно целого числа, вы можете использовать:

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

столько раз, сколько захочешь.Использование функции-оболочки оправдано только потому, что максимальное значение является эксклюзивным - я знаю, что случайные числа работают таким образом, но определение .Next сбивает с толку.

Создавать генератор каждый раз, когда вам нужно число, на мой взгляд, неправильно;псевдослучайные числа таким образом не работают.

Во-первых, вы сталкиваетесь с проблемой инициализации, которая обсуждалась в других ответах.Если вы инициализируете один раз, у вас не возникнет этой проблемы.

Во-вторых, я совсем не уверен, что вы получаете правильную последовательность случайных чисел;скорее, вы получаете набор из первого числа нескольких различных последовательностей, которые заполняются автоматически в зависимости от компьютерного времени.Я не уверен, что эти числа пройдут тесты, подтверждающие случайность последовательности.

Dim rnd As Random = New Random
rnd.Next(n)

Просто для справки, определение СЕТЕВОЙ функции VB для RND и RANDOMIZE (которое должно давать те же результаты, что и BASIC (1980-е годы) и все версии после 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

В то время как Случайный КЛАСС является:

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
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] Это лучший способ, с нуля: P

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top