سؤال

أحتاج إلى إنشاء عدد صحيح عشوائي بين 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 بشكل أكبر، بالإضافة إلى أنه أقصر في الكتابة، ولكنه يناسبك.)

أرى مشكلتين محتملتين في هذه الطريقة، لكنها ستكون مناسبة (وصحيحة) لمعظم الاستخدامات.لذلك إذا كنت تريد أ بسيط الحل أعتقد أن هذا هو الصحيح

المشكلتان الوحيدتان اللتان أراهما في هذه الوظيفة هما:1:عندما يكون Max = Int32.MaxValue، فإن إضافة 1 يؤدي إلى إنشاء تجاوز رقمي.وعلى الرغم من أن هذا سيكون نادرا، فإنه لا يزال احتمالا.2:عند الحد الأدنى > الحد الأقصى + 1.عندما يكون الحد الأدنى = 10 والحد الأقصى = 5، فإن الدالة التالية تطرح خطأ.قد يكون هذا ما تريد.ولكن قد لا يكون كذلك.أو فكر في متى يكون الحد الأدنى = 5 والحد الأقصى = 4.بإضافة 1، يتم تمرير 5 إلى الطريقة التالية، لكنها لا تؤدي إلى حدوث خطأ، في حين أنه خطأ بالفعل، ولكن كود Microsoft .NET الذي قمت باختباره يُرجع 5.لذا فهو في الحقيقة ليس حدًا أقصى "حصريًا" عندما يكون الحد الأقصى = الحد الأدنى.ولكن عندما يكون الحد الأقصى < دقيقة للدالة Random.Next()، فإنه يطرح ArgumentOutOfRangeException.لذا فإن تطبيق Microsoft غير متسق حقًا وعربات التي تجرها الدواب أيضًا في هذا الصدد.

قد ترغب ببساطة في تبديل الأرقام عند min > max حتى لا يتم ظهور أي خطأ، لكن ذلك يعتمد كليًا على ما هو مرغوب فيه.إذا كنت تريد خطأً في القيم غير الصالحة، فمن الأفضل أيضًا أن ترمي الخطأ عندما يكون الحد الأقصى الحصري لـ Microsoft (الحد الأقصى + 1) في الكود الخاص بنا يساوي الحد الأدنى، حيث يفشل MS في الخطأ في هذه الحالة.

يعد التعامل مع الحل البديل عندما يكون max = Int32.MaxValue غير مريح بعض الشيء، لكنني أتوقع نشر وظيفة شاملة تتعامل مع كلتا الحالتين.وإذا كنت تريد سلوكًا مختلفًا عن الطريقة التي قمت بتشفيرها، فتناسب نفسك.ولكن كن على علم بهاتين المسألتين.

ترميز سعيد!

يحرر:لذلك كنت بحاجة إلى مولد أعداد صحيحة عشوائي، وقررت ترميزه "بشكل صحيح".لذلك، إذا كان أي شخص يريد الوظيفة الكاملة، فإليك الوظيفة التي تعمل بالفعل.(لكنه لا يفوز بالجائزة الأبسط بسطرين فقط من التعليمات البرمجية.لكنها ليست معقدة حقًا أيضًا.)

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

مثال مايكروسوفت وظيفة 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)

ثم يمكن أن تعود النتيجة كما هي مرارًا وتكرارًا لأنها تعالج المكالمة بسرعة كبيرة.ربما لم تكن هذه مشكلة في عام 2008، ولكن نظرًا لأن المعالجات أصبحت أسرع كثيرًا اليوم، فإن الوظيفة لا تسمح لساعة النظام بالوقت الكافي للتغيير قبل إجراء المكالمة الثانية.

بما أن الدالة 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 NET Fuction لـ RND و RANDOMIZE (والذي يجب أن يعطي نفس نتائج BASIC (1980 عامًا) وجميع الإصدارات اللاحقة هو:

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] هذه هي أفضل طريقة ، من الصفر: ص

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top