Melona380 Melona380 - 1 month ago 8
Vb.net Question

Visual Basic Divide Double Randomly based on Divisor

Ok, so I want to divide a number randomly not evenly...
so lets say we have 20 I need 5 (Divisor) random chunks of 20.


4 4 4 4 4


Instead I want something like


6 2 4 3 5


It cant exceed the starting number

How can this be accomplished in vb?

Please help, Been stuck for hours.

Answer
Public Iterator Function DivideUp(ByVal Number As Integer, ByVal Groups As Integer, Optional ByVal Variance As Integer = 5) As IEnumerable(Of Integer)
    Dim rnd As New Random()

    While Groups > 0 AndAlso Number > 0 
       If Groups = 1 Then
           Yield Number
           Exit Function
       End If
       If Variance > Number - Groups Then Variance = Number - Groups

       Dim temp As Integer = Number / Groups
       temp += rnd.Next(Variance * -1, Variance)

       Yield temp
       Number -= temp
       Groups -= 1
    End While
End Function

Call it like this:

For Each num As Integer In DivideUp(20, 5)
    Console.WriteLine(num)
Next

Something more conventional:

Public Function DivideUp(ByVal Number As Integer, ByVal Groups As Integer, Optional ByVal Variance As Integer = 5) As Integer()
    Static rnd As New Random()

    Dim result(Groups-1) As Integer
    For i As Integer = 0 To Groups - 1
       If Variance > Number - Groups Then Variance = Number - Groups
       If i = Groups - 1 Then
           result(i) = Number
       Else
           Dim temp As Integer = Number / Groups
           temp += rnd.Next(Variance * -1, Variance)
           result(i) = temp
           Number -= temp
       End If
    Next i
    Return result
End Function

If you want to get real fancy, you could use a log or natural log of your random variance to try make it more likely to stay closer to the median, ie: if your number divides evenly into groups of 4, do you want it to be rarer to see a 2 than a 3, rarer to see a 1 than a 2?

Finally, a test harness:

Dim errorCount As Integer = 0
For i As Integer = 0 To 10000
    Dim items = DivideUp(100, 12)
    Dim sum As Integer = 0 
    For Each j As Integer In items
        Console.Write(j)
        Console.Write(" ")
        sum += j
    Next j   
    Console.WriteLine("Total: {0}", sum)
    If sum <> 100 Then
        errorCount += 1
        Dim tempColor = Console.ForegroundColor
        Console.ForegroundColor = ConsoleColor.Red
        Console.WriteLine("Error: incorrect total!")
        Console.ForegroundColor = tempColor
    End If     
Next i
If errorCount > 0 Then
    Dim tempColor = Console.ForegroundColor
    Console.ForegroundColor = ConsoleColor.Red
    Console.WriteLine("Error: incorrect total on {0} tries!")
    Console.ForegroundColor = tempColor
End If

If you're working with real money, you need to use a cryptographic random number generator (the simple Random type won't cut it) and you want to actually save each of these results (plus run it more like a few million times than just 10,000). Then you pull that data into something like R and graph your distributions, to make sure things flat (evenly distributed) with no visible bias. And you have to do this for a number of different Number/Group/Variance combinations. Failure to rigorously validate the randomness the purge any bias will result in someone gaming your system to win much more often than they should.