2020vision
2020vision

Reputation: 11

Sum of Random numbers must be greater than x and less than y

I would like for my code to express the sum of random numbers generated to be in a range. Between 120 and 235.
What's the best way to do that without changing my code too much?

I'm positive it needs to create 2 Dims and an if else statement, but I can't word it properly.
I'm using Visual Studio 2017

Public Class Form1

    Private Sub Button1_Click(ByVal sender As Object, e As EventArgs) Handles Button1.Click
        Randomize()

        TextBox1.Text = Rand(1, 100)
        TextBox2.Text = Rand(Long.Parse(TextBox1.Text), 100)
        TextBox3.Text = Rand(Long.Parse(TextBox2.Text), 100)
        TextBox4.Text = Rand(Long.Parse(TextBox3.Text), 100)
        TextBox5.Text = Rand(Long.Parse(TextBox4.Text), 100)
        TextBox6.Text = Rand(Long.Parse(TextBox5.Text), 100)
    End Sub

    Private Function Rand(v As Long) As String
        Throw New NotImplementedException()
    End Function

    Private Function Rand(ByVal Low As Long, ByVal High As Long) As Long
        Rand = Int((High - Low + 1) * Rnd()) + Low
    End Function
End Class

Upvotes: 0

Views: 424

Answers (2)

Jimi
Jimi

Reputation: 32248

I'ld suggest to use the .Net Random class to generate random numbers. It's also simpler to use.

Find the first random number between 0 and the Minimum value, then the second random number will be in range: randomMin(MinValue) => (MinValue - randomMin, MaxValue - randomMin):

randomMin = rnd1.Next(Min + 1)
randomMax = rnd2.Next(Min - randomMin, Max - randomMin + 1)
result = randomMin + randomMax

To remember that, in the Random class, the upper limit is exclusive, so we need to add 1 to the Max value to include it in the range of random values.


Make a sample test:
(These code samples suppose that the VB.Net version in use is at least V.14, VS 2015+)

Private rnd1 As Random = New Random()
Private rnd2 As Random = New Random()

'(...)

Dim Min As Integer = 120
Dim Max As Integer = 235

For i = 0 To 100
    Dim randomValues = GetRandomNumbersInRange(Min, Max)
    Console.WriteLine($"Random Min: {randomValues.rndMin} Random Max {randomValues.rndMax}")
    Console.WriteLine($"Sum: {randomValues.rndMin + randomValues.rndMax}")
Next

'(...)

Private Function GetRandomNumbersInRange(Min As Integer, Max As Integer) As 
                                        (rndMin As Integer, rndMax As Integer)
    Dim randomMin As Integer = rnd1.Next(Min + 1)
    Return (randomMin, rnd2.Next(Min - randomMin, Max - randomMin + 1))
End Function

If you want the method to directly return the sum, you could change the method return type like this:

Dim Min As Integer = 120
Dim Max As Integer = 235

For i = 0 To 100
    Console.WriteLine(GetSumRandomNumbersInRange(Min, Max))
Next

'(...)

Private Function GetSumRandomNumbersInRange(Min As Integer, Max As Integer) As Integer
    Dim randomMin As Integer = rnd1.Next(Min + 1)
    Return randomMin + rnd2.Next(Min - randomMin, Max - randomMin + 1)
End Function

The random numbers could also be selected with:
randomMid(MaxValue - MinValue) => (MinValue, MaxValue - randomMid)

It this case, possibly implemented as:

Private Function GetSumRandomNumbersInRange2(Min As Integer, Max As Integer) As Integer
    Dim randomFirst As Integer = rnd1.Next(Max - Min + 1)
    Return randomFirst + rnd2.Next(Min, Max - randomFirst + 1)
End Function

Upvotes: 1

jmcilhinney
jmcilhinney

Reputation: 54417

Here is the algorithm I would use to accomplish this task:

  1. Generate a single random number in the range 120 to 235. That will be the final sum.
  2. Generate six random numbers in the range 0.0 to 1.0.
  3. Normalise those six numbers, i.e. divide each by the sum of all six.
  4. Multiply each of the six normalised numbers by the original random number.
  5. Round each of the six results.

You now have six random numbers with a sum in the desired range. You may just need to add or subtract 1 to one of the values in case rounding has pushed the sum outside the range. You can choose one of the numbers at random to adjust.

'Create a random number generator.
Dim rng As New Random

'Create a random number in the desired range for the final sum.
Dim sum = rng.Next(120, 235 + 1)

'Generate six proportional values as fractions of 1.0.
Dim proportions = Enumerable.Range(1, 6).Select(Function(n) rng.NextDouble()).ToArray()

'Get the sum of all the proportional values.
Dim proportionsSum = proportions.Sum()

'Normalise the proportional values so that they sum to 1.0
proportions = Array.ConvertAll(proportions, Function(r) r / proportionsSum)

'Break the final sum up into the specified proportions.
Dim numbers = Array.ConvertAll(proportions, Function(r) CInt(Math.Round(r * sum)))

'Adjust as required if rounding has pushed the sum below the minimum value.
Do While numbers.Sum() < 120
    'Get a random element index.
    Dim index = rng.Next(0, numbers.Length)

    'Increment the element at that index.
    numbers(index) = numbers(index) + 1
Loop

'Adjust as required if rounding has pushed the sum above the maximum value.
Do While numbers.Sum() > 235
    'Get a random element index.
    Dim index = rng.Next(0, numbers.Length)

    'Decrement the element at that index.
    numbers(index) = numbers(index) - 1
Loop

'The numbers array now contains six random values with a sum in the range 120 to 235.

Upvotes: 0

Related Questions