Pergunta

Preciso gerar um número inteiro aleatório entre 1 e n (onde n é um número inteiro positivo) para usar em um teste de unidade.Não preciso de algo muito complicado para garantir a verdadeira aleatoriedade - apenas um número aleatório antiquado.

Como eu faria isso?

Foi útil?

Solução

Para obter um valor inteiro aleatório entre 1 e N (inclusive), você pode usar o seguinte.

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

Outras dicas

Como já foi apontado muitas vezes, a sugestão de escrever código como este é problemática:

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

A razão é que o construtor do Random class fornece uma semente padrão baseada no relógio do sistema.Na maioria dos sistemas, isso tem granularidade limitada – algo em torno de 20 ms.Portanto, se você escrever o código a seguir, obterá o mesmo número várias vezes seguidas:

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

O código a seguir aborda esse problema:

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

Elaborei um programa simples usando ambos os métodos para gerar 25 números inteiros aleatórios entre 1 e 100.Aqui está o resultado:

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

Usar Sistema.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)

Todas as respostas até agora apresentam problemas ou bugs (plural, não apenas um).Eu vou explicar.Mas primeiro quero elogiar o insight de Dan Tao de usar uma variável estática para lembrar a variável Generator, de modo que chamá-la várias vezes não repetirá o mesmo # indefinidamente, além de ele ter dado uma explicação muito boa.Mas seu código sofreu a mesma falha que a maioria dos outros, como explico agora.

A MS tornou seu método Next() bastante estranho.o parâmetro Min é o mínimo inclusivo como seria de esperar, mas o parâmetro Max é o exclusivo máximo como NÃO seria de esperar.em outras palavras, se você passar min=1 e max=5 então seus números aleatórios seriam 1, 2, 3 ou 4, mas nunca incluiriam 5.Este é o primeiro de dois possíveis bugs em todo o código que usa o método Random.Next() da Microsoft.

Para simples resposta (mas ainda com outros problemas possíveis, mas raros), então você precisará usar:

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

(eu gosto de usar Int32 em vez de Integer porque deixa mais claro o tamanho do int, além de ser mais curto para digitar, mas fique à vontade.)

Vejo dois problemas potenciais com este método, mas será adequado (e correto) para a maioria dos usos.Então se você quiser um simples solução, acredito que esteja correto.

Os únicos 2 problemas que vejo com esta função são:1:quando Max = Int32.MaxValue, adicionar 1 cria um estouro numérico.embora isso seja raro, ainda é uma possibilidade.2:quando mínimo > máximo + 1.quando min = 10 e max = 5, a função Next gera um erro.isso pode ser o que você deseja.mas também pode não ser.ou considere quando min = 5 e max = 4.adicionando 1, 5 é passado para o método Next, mas não gera um erro, quando na verdade é um erro, mas o código Microsoft .NET que testei retorna 5.então realmente não é um máximo 'exclusivo' quando o máximo = o mínimo.mas quando max <min para a função Random.Next(), ela lança uma ArgumentOutOfRangeException.portanto, a implementação da Microsoft também é realmente inconsistente e problemática nesse aspecto.

você pode querer simplesmente trocar os números quando min > max para que nenhum erro seja gerado, mas depende totalmente do que é desejado.se você deseja um erro em valores inválidos, provavelmente é melhor lançar o erro também quando o máximo exclusivo da Microsoft (máx. + 1) em nosso código for igual ao mínimo, onde a MS não comete erro neste caso.

lidar com uma solução alternativa para quando max = Int32.MaxValue é um pouco inconveniente, mas espero postar uma função completa que lide com essas duas situações.e se você quiser um comportamento diferente do que eu codifiquei, faça como quiser.mas esteja ciente desses 2 problemas.

Boa codificação!

Editar:Então, eu precisava de um gerador de números inteiros aleatórios e decidi codificá-lo 'correto'.Então, se alguém quiser a funcionalidade completa, aqui está uma que realmente funciona.(Mas não ganha o prêmio mais simples com apenas 2 linhas de código.Mas também não é muito complexo.)

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

Exemplo da Microsoft Função Rnd

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

1- Inicialize o gerador de números aleatórios.

Randomize()

2 - Gere valor aleatório entre 1 e 6.

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

Se você estiver usando a resposta de Joseph, que é uma ótima resposta, e você as executar consecutivamente assim:

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

Então, o resultado pode voltar a ser o mesmo repetidamente porque processa a chamada muito rapidamente.Isso pode não ter sido um problema em 2008, mas como os processadores são muito mais rápidos hoje, a função não permite que o relógio do sistema tenha tempo suficiente para mudar antes de fazer a segunda chamada.

Como a função System.Random() é baseada no relógio do sistema, precisamos dar tempo suficiente para que ele mude antes da próxima chamada.Uma maneira de fazer isso é pausar o thread atual por 1 milissegundo.Veja exemplo abaixo:

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

Você deve criar um gerador de números pseudoaleatórios apenas uma vez:

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

Então, se um número inteiro for suficiente para suas necessidades, você poderá usar:

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

quantas vezes quiser.O uso da função wrapper é justificado apenas porque o valor máximo é exclusivo - sei que os números aleatórios funcionam dessa maneira, mas a definição de .Next é confusa.

Criar um gerador sempre que você precisar de um número é, na minha opinião, errado;os números pseudo-aleatórios não funcionam desta forma.

Primeiro, você obtém o problema de inicialização que foi discutido nas outras respostas.Se você inicializar uma vez, não terá esse problema.

Em segundo lugar, não tenho certeza de que você obtenha uma sequência válida de números aleatórios;em vez disso, você obtém uma coleção do primeiro número de múltiplas sequências diferentes que são propagadas automaticamente com base no tempo do computador.Não tenho certeza se esses números passarão nos testes que confirmam a aleatoriedade da sequência.

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

Apenas para referência, a definição de função VB NET para RND e RANDOMIZE (que deve fornecer os mesmos resultados do BASIC (1980 anos) e de todas as versões posteriores é:

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

Enquanto a CLASSE Aleatória é:

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] Esta é a melhor maneira, do zero: P

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top