Public Class Form1
Dim x As Integer
Dim y(9) As Double
Dim average As Double
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For x = 0 To 9
y(x) = x
Next
average = y(9) / 10
Label1.Text = average
End Sub
End Class
I'm having trouble trying to calculate the average of 0 to 9 array, I realize that my code is only going to calculate 9 divided by 10, How do I proceed with calculating the average of the 10 numbers?
Use Linq...
Dim average As Double = y.Average()
Another thing you can do with Linq is exclude certain values from your average. Take this example that sets 9 items in myNumbers() to 10 and then sets the 10th one to zero. I use Linq to first filter for numbers greater than zero then I perform the Average aggregate.
Dim myNumbers(9) As Double
For i As Integer = 0 To 8 Step 1
myNumbers(i) = 10
Next i
myNumbers(9) = 0
Dim average As Double = myNumbers.Where(Function(num) num > 0).Average()
'Optionally, you could also do it this way:
Dim average2 As Double = (From num In myNumbers
Where num > 0).Average()
MessageBox.Show(average)
It gets even better when you use classes. Consider this class Thing:
Public Class Thing
Public Name As String = ""
Public Number As Double = 0
Public Sub New (name As String, number As Double)
Me.Name= name
Me.Number = number
End Sub
End Class
I can create a collection of that class and the .Where becomes even more powerful. In this example I'm averaging Thing.Number by Thing.Name
Dim things As List(Of Thing) = New List(Of Thing)()
things.Add(New Thing("Michael", 10))
things.Add(New Thing("Michael", 5))
things.Add(New Thing("Michael", 7))
things.Add(New Thing("Michael", 9))
things.Add(New Thing("Rian", 10))
things.Add(New Thing("Rian", 10))
things.Add(New Thing("Rian", 10))
Dim AverageMichael As Double = things.Where(Function(thing) thing.Name = "Michael").Average(Function(thing) thing.Number)
Dim AverageRian As Double = things.Where(Function(thing) thing.Name = "Rian").Average(Function(thing) thing.Number)
MessageBox.Show(AverageMichael)
MessageBox.Show(AverageRian)
A side note
If you're a .NET developer and you'd like to learn to use Linq or you simply need an easy environment to test .NET code then I highly recommend LinqPad. I used LinqPad for all the code in this post.
http://www.linqpad.net/
The average of a set of values is equals to the sum of values divided by the number of values.
You need to declare a variable sum to add every value of your array and then divide by 10.
You need to sum all the values and then divide. I recomend using a simple function for it:
Function getAverage(y As Double()) As Double
Dim z As Double
For Each i As Double In y
z += i
Next
Return z / y.Length
End Function
Just set the average to getAverage(y)
Related
I'm a beginner working on my first application using Visual Basic in Visual Studio 2019.
I want to calculate this:
I have all Wi in (list view) and also (text box).
I have all Hi in (list view).
My problem is how could I multiply wi list view (or Wi text box) by hi list view and get this result in a third list view ?
I expect that the biggest problem you have found is getting the data from the ListViews - please note that using a Control to store data is usually a bad idea.
Note that array indexes in VB.NET (and C# and many other computer languages) start at zero (i.e. they are offsets, rather than indices as used in maths).
Once you have the data in arrays, it is easy to perform the calculation. Coming up with meaningful names for the methods and variables is also a problem.
With ListViews named ListViewW, ListViewH, and ListViewF I came up with this:
Public Class Form1
Dim rand As New Random()
Function Fvalues(Fb As Double, weights As Double(), values As Double()) As Double()
If weights.Length <> values.Length Then
Throw New ArgumentException("Number of weights does not equal number of values.")
End If
'TODO: Possibly more argument checking.
Dim total = 0.0
For i = 0 To weights.Length - 1
total += weights(i) * values(i)
Next
'TODO: Check for total = 0.
Dim F(weights.Length - 1) As Double
For i = 0 To weights.Length - 1
F(i) = Fb * weights(i) * values(i) / total
Next
Return F
End Function
Function ListViewToDoubles(lv As ListView) As Double()
Dim d As New List(Of Double)
For i = 0 To lv.Items.Count - 1
Dim dbl As Double
If Double.TryParse(lv.Items(i).Text, dbl) Then
d.Add(dbl)
End If
Next
Return d.ToArray()
End Function
Sub CreateSampleData()
For i = 1 To 5
ListViewW.Items.Add(rand.NextDouble().ToString())
ListViewH.Items.Add(rand.Next(0, 11).ToString())
Next
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
CreateSampleData()
Dim weights = ListViewToDoubles(ListViewW)
Dim values = ListViewToDoubles(ListViewH)
Dim f = Fvalues(0.5, weights, values)
For Each x In f
ListViewF.Items.Add(x.ToString())
Next
End Sub
End Class
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
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
Here is the algorithm I would use to accomplish this task:
Generate a single random number in the range 120 to 235. That will be the final sum.
Generate six random numbers in the range 0.0 to 1.0.
Normalise those six numbers, i.e. divide each by the sum of all six.
Multiply each of the six normalised numbers by the original random number.
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.
I'm working on a histogram class and in particular a binning method.
In relation hereto I have two questions:
Is it a right/appropriate algorithm seen from a logic/statistical point of view
Is the code optimal or at least decent - please tell me how to improve it
Any help is highly appreciated - thx in advance.
Here is my code so far...
Public Class Histo
Dim data() As Double
Dim bins As Integer = 0
Dim bw As Double = 0
Dim _min As Double = 0
Dim _max As Double = 0
Dim arrMax As Double = 0
Dim cht As Chart
Public shared Decimals As Integer
Public Sub New(_arr() As Double, _cht As Chart)
'One-dimensional array as data
data = _arr
'No of bins with Sturges method
bins = NoBin_ST(data)
'calculate bin width
bw = Range(data) / bins
'bin boundries for first bin
_min = Min(data)
_max = _min + bw
'max of data
arrMax = Max(data)
'chart object
cht = _cht
'no of decimals on x-axis
Decimals = Dec
End Sub
Public Function Binning() As Integer()
'Binning "algorihtm" for continuous data
'
'RETURN: one-dimensional array with n bins
'
Array.Sort(data)
Dim j As Integer = 0
Dim mn As Double = _min
Dim mx As Double = _max
Dim counter(bins-1) As Integer
For i As Integer = 0 To data.GetLength(0)-1
'check if data point is within the boundries of the current bin
If data(i) >= mn AndAlso data(i) < mx Then
'add counter in current bin
counter(j) += 1
Else
'special case: at the end at least one data point will equal max of the last bin
' and must be counted in that bin
If data(i) = arrMax Then
counter(j) += 1
Continue For
End If
'the data point has exceeded the boundries of the previous bin
' and must be counted in the next bin
'min and max is increased with the bin width
mn += bw
mx += bw
'go to next bin
j += 1
'count data point in this bin and loop again
counter(j) += 1
End If
Next
Return counter
End Function
.....
Not sure if this is any more performant, but I think it is a bit simpler.
Function CreateBins(values As IEnumerable(Of Double), numberOfBins As Integer) As IGrouping(Of Integer, Double)()
If values Is Nothing Then Throw New Exception("Values cannot be null")
If values.Distinct.Count < 2 Then Throw New Exception("Values must contain at least two ditinct elements")
If numberOfBins < 1 Then Throw New Exception("numberOfBins must be an integer > 1")
Dim min = values.Min
Dim max = values.Max
Dim binSize = (max - min) / numberOfBins
' Checking for two distinct elements should eliminate possibility of min=max and therefore binsize=0
Dim bins = values.GroupBy(Function(x) Convert.ToInt32(Math.Floor((x - min) / binSize))).ToArray
' Group counts available using the ienumerable Count function
' Dim counts = bins.Select(Function(x) x.Count)
' Or retaining the group key
' Dim counts = bins.Select(Function(x) New With {Key x.Key, x.Count})
Return bins
End Function
Each bin is now a group. The original values are retained as part of the group, allowing potential follow up analysis. Count is available using the group function Count()
I recently wrote this program in Visul Basic 13.
it searchs for the nth catalan number but after 48 even Decimal type is too short.
Is there any other way to represent them? like in the form of A*10^n?
Public Class Try_Catalan_Number
'Catalan numbers form a sequence of natural numbers that occur in various counting problems,
'often involving recursively defined objects.
Inherits Base_Number
Public Overrides Sub Test()
Dim Return_Catalan_Value As Decimal
If Function_Catalan(Return_Catalan_Value) = False Then
Return_To_Form_Boolean = False
Else
Return_To_Form_Boolean = True
End If
Return_To_Form_Value = Function_Catalan(Return_Catalan_Value)
End Sub
Private Function Function_Catalan(Return_Catalan_Value As Decimal) As Decimal
'We return a Decimal function because catalan numbers can be very big and decimal is the biggest type.
Dim Binomial_Cofficients As Decimal
Dim Result As Decimal
Dim Number_Of_Loops As Integer
Dim tmpNumber As Object
Dim K As Decimal
Dim N As Decimal
If (Number > 48) Then
Return False
Exit Function
End If
'48 is the largest catalan number position which can be displayed...any position above 48 is too big.
tmpNumber = Number - 1
N = 2 * tmpNumber
K = tmpNumber
Result = 1
For Number_Of_Loops = 1 To K
Result = Result * (N - (K - Number_Of_Loops))
Result = Result / Number_Of_Loops
Next Number_Of_Loops
Binomial_Cofficients = Result
tmpNumber = Number - 1
tmpNumber = ((1 / (1 + tmpNumber)) * Binomial_Cofficients)
Return_Catalan_Value = tmpNumber
Return Return_Catalan_Value
End Function
End Class
[I assume by "Visul Basic 13" you mean the VB which is associated with Visual Studio 2013, i.e. VB version 12.0.]
You can use System.Numerics.BigInteger (you'll have to add a reference to System.Numerics):
Imports System.Numerics
Module Module1
Friend Function Factorial(n As Integer) As BigInteger
If n < 2 Then Return 1
If n = 2 Then Return 2
Dim f As BigInteger = BigInteger.Parse("2")
For i = 3 To n
f *= i
Next
Return f
End Function
Friend Function CatalanNumber(n As Integer) As BigInteger
Return Factorial(2 * n) / (Factorial(n + 1) * Factorial(n))
End Function
Sub Main()
For i = 0 To 550
Console.WriteLine(CatalanNumber(i).ToString())
Next
Console.ReadLine()
End Sub
End Module
I did not test to see the maximum Catalan number it can calculate, and I have no inclination to verify the results beyond those shown on the Wikipedia page.
Optimisations are left as an exercise for the reader ;)
Edit: FWIW, I can get it to run a bit faster by using
Function CatalanNumber(n As Integer) As BigInteger
Dim nFactorial = Factorial(n)
Dim twonFactorial = nFactorial
For i = (n + 1) To 2 * n
twonFactorial = BigInteger.Multiply(twonFactorial, i)
Next
Return twonFactorial / (BigInteger.Pow(nFactorial, 2) * (n + 1))
End Function
The speed increase varies from roughly 50% (n=50) to 20% (n=5000). If you're only using the function a few times for fairly small n, there may be little point worrying about it.
Edit2 Re-writing your function a bit to make it easier to read and removing the off-by-one error, we get:
Private Function Function_Catalan(a As Integer) As BigInteger
If a = 0 Then Return 1
Dim binomialCofficient As BigInteger = BigInteger.One
Dim n As Integer = 2 * a
Dim k As Integer = a - 1
For i As Integer = 1 To k
binomialCofficient = binomialCofficient * (n - (k - i)) / i
Next i
Return binomialCofficient / a
End Function
to get this format you could use:
String.Format("{0:E4}", InputNumber)
Hi I am new to VB and I have problems with using array. My code is like that.
This is class FindFactorsObject.vb
Public Sub FindFactors()
count = 0
temp = Convert.ToInt32(Math.Sqrt(_x))
For i As Integer = 1 To temp
If _x Mod i = 0 Then
ReDim array(count)
array(count) = i
count += 1
End If
Next
So I created an array and stored the results. Now I want to display each value in my array in Form.vb and if it is possible can somebody teach me how to make delay for each of the displayed value. Thanks very much
Always declare your variables, if possible to their exact types, you think they will take care of. When you say 'Now I want to display each value in my array in Form.vb' I understood literally: in the Form so, we will print them on your form
Public Sub FindFactors(_x As Integer)
Dim temp As Integer = Convert.ToInt32(Math.Sqrt(_x))
Dim l As New List(Of Integer)
For i As Integer = 1 To temp
If _x Mod i = 0 Then
l.add(i)
End If
Next
Dim pf As New PointF(20, 20)
For Each i As Integer In l
creategraphics.drawstring(i.ToString, New font(font.fontFamily, 24), brushes.cadetblue, pf)
pf = New PointF(pf.X, pf.Y + 30)
Next
End Sub