Link to home
Start Free TrialLog in
Avatar of Rowel Virgo
Rowel VirgoFlag for Philippines

asked on

How to get random numbers with percent to show

Hi i'm creating a program in vb that can generate random numbers. the thing is i want to lessen the chance to appear the highest number.

for Example i have numbers from 1-10 (in ramdom)

Number 10 the chance to appear is 10%
Number 9 the chance to appear is 20%
Number 8 the chance to appear is 30%
etc..

here is my sample code.
        Dim R1 As New Random
        Dim d1result1 As Integer = R1.Next(1, 10)
        Label2.Text = d1result1.ToString

Open in new window


I want 1,2,3,4,5 appears more often
and 6,7,8,9,10 has less chance to appears.
Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

So do you want random numbers or not?  Because weighting some numbers means they are not random.
Well, it is pretty simple..

Module Module1
    Sub Main()
        Dim Generator As New Random
        Dim Weights() As Long = New Long(9) {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))

        Console.WriteLine("Done.")
        Console.ReadLine()
    End Sub

    Function WeightedRandom(AWeights() As Long, AGenerator As Random) As Long
        Dim MapCount As Long
        Dim MapIndex As Long
        Dim Range As Long = AWeights.Sum()
        Dim WeightCount As Long
        Dim Map(Range - 1) As Long

        MapIndex = 0
        For WeightCount = 0 To UBound(AWeights)
            For MapCount = 1 To AWeights(WeightCount)
                Map(MapIndex) = WeightCount
                MapIndex = MapIndex + 1
            Next
        Next

        WeightedRandom = Map(AGenerator.Next(0, Range - 1))
    End Function
End Module

Open in new window

One way to achieve this is with an array.
The array elements will hold the chances of you number to get choosen.
The array index will be the desired number

Sample below:
Public Function weightedRandomNumber() As Integer
    Const MIN As Integer = 1
    Const MAX As Integer = 100
    Dim numbers(1 To 10) As Integer
    numbers(1) = 15
    numbers(2) = 30
    numbers(3) = 45
    numbers(4) = 60
    numbers(5) = 75
    numbers(6) = 80
    numbers(7) = 85
    numbers(8) = 90
    numbers(9) = 95
    numbers(10) = 100
    
    Randomize
    Dim randomValue As Integer
    randomValue = (MAX - MIN + 1) * Rnd + 1
    
    Dim i As Integer
    For i = 1 To 10
        If (randomValue < numbers(i)) Then
            weightedRandomNumber = i
            Exit For
        End If
    Next
End Function

Open in new window

Ops, didn't notice it was .Net.
Well, hope you'll get the idea.
@Fabrice: But it requires careful calculation of your array..

Dim Weights() As Long = New Long() {3, 1, 2}     vs   Dim numbers() As Long = New Long() {50, 67, 100}

Module Module1
    Sub Main()
        Dim Generator As New Random
        Dim Weights() As Long = New Long() {3, 1, 2}

        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))
        Console.WriteLine(WeightedRandom(Weights, Generator))

        Console.WriteLine("--")

        Dim numbers() As Long = New Long() {50, 67, 100}
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))
        Console.WriteLine(WeightedRandom2(numbers, Generator))

        Console.WriteLine("Done.")
        Console.ReadLine()
    End Sub

    Function WeightedRandom(AWeights() As Long, AGenerator As Random) As Long
        Dim MapCount As Long
        Dim MapIndex As Long
        Dim Range As Long = AWeights.Sum()
        Dim WeightCount As Long
        Dim Map(Range - 1) As Long

        MapIndex = 0
        For WeightCount = 0 To UBound(AWeights)
            For MapCount = 1 To AWeights(WeightCount)
                Map(MapIndex) = WeightCount
                MapIndex = MapIndex + 1
            Next
        Next

        WeightedRandom = Map(AGenerator.Next(0, Range - 1)) + 1
    End Function

    Function WeightedRandom2(AWeights() As Long, AGenerator As Random) As Long
        Dim index As Long
        Dim randomValue As Long = AGenerator.Next(1, 100)

        WeightedRandom2 = -1
        For index = 0 To UBound(AWeights)
            If (randomValue < AWeights(index)) Then
                WeightedRandom2 = index + 1
                Exit For
            End If
        Next
    End Function
End Module

Open in new window


p.s. it must be

WeightedRandom = Map(AGenerator.Next(0, Range - 1)) + 1

Open in new window

in my function, otherwise it is off by one.
@ste5an:
@Fabrice: But it requires careful calculation of your array..
Yeah, ehence why it is "one way to achieve it".
omg, still of by one, should have rtfm first, the upper boundary of Next() is exclusive:

Function WeightedRandom(AWeights() As Long, AGenerator As Random) As Long
    Dim MapCount As Long
    Dim MapIndex As Long
    Dim Range As Long = AWeights.Sum()
    Dim WeightCount As Long
    Dim Map(Range - 1) As Long

    MapIndex = 0
    For WeightCount = 0 To UBound(AWeights)
        For MapCount = 1 To AWeights(WeightCount)
            Map(MapIndex) = WeightCount
            MapIndex = MapIndex + 1
        Next
    Next

    WeightedRandom = Map(AGenerator.Next(0, Range)) + 1
End Function

Function WeightedRandom2(AWeights() As Long, AGenerator As Random) As Long
    Dim index As Long
    Dim randomValue As Long = AGenerator.Next(1, 101)

    WeightedRandom2 = -1
    For index = 0 To UBound(AWeights)
        If (randomValue < AWeights(index)) Then
            WeightedRandom2 = index + 1
            Exit For
        End If
    Next
End Function

Open in new window

I expanded your specification list and see that you might want to explain how often you see a 1
10	10%
9	20%
8	30%
7	40%
6	50%
5	60%
4	70%
3	80%
2	90%
1	100%

Open in new window

In a 100 of 550 cases.. or so ;)
SOLUTION
Avatar of Ark
Ark
Flag of Russian Federation image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Just don't forget any numbers generated like this are not random.  For a number to be random then it must have an equal chance with any other number in the desired range.
No comment has been added to this question in more than 21 days, so it is now classified as abandoned.

I have recommended this question be closed as follows:

Split:
-- ste5an (https:#a42539675)
-- Ark (https:#a42539448)


If you feel this question should be closed differently, post an objection and the moderators will review all objections and close it as they feel fit. If no one objects, this question will be closed automatically the way described above.

MacroShadow
Experts-Exchange Cleanup Volunteer