Parallel.For VS For. Why there is this difference? - vb.net

I have an array (i), and I want to do some math calculations based on the i value with a Parallel.For().
But the problem is, after running the Parallel.For(), the values on my array are still 0.
This happens when my for is from 0 to 0.
This is my code :
Dim a(10) As Double
Parallel.For(0, 0, Sub(i)
a(i) = i + 2
'There is some calculations based on instead of previous line!
'But anyway, the result will be on a(i).
End Sub)
MessageBox.Show(a(0)) 'This returns 0!
For i As Integer = 0 To 0
a(i) = i + 2
Next
MessageBox.Show(a(0)) 'But this returns 2!
What is the problem?

From Microsoft's documentation
If fromInclusive is greater than or equal to toExclusive, then the method returns immediately without performing any iterations.
Therefore nothing will happen when you use Parallel.For(0,0,etc).
Try Parallel.For(0,1) and see if you get a result.

Your correct code should look like this
Dim a(10) As Double
Parallel.For(0, 1, Sub(i)
a(i) = i + 2
'There is some calculations based on instead of previous line!
'But anyway, the result will be on a(i).
End Sub)
MessageBox.Show(a(0)) '2!
For i As Integer = 0 To 0
a(i) = i + 2
Next
MessageBox.Show(a(0)) '2

Related

Random number creating

I got some help from one, and the code works perfectly fine.
What im looking for, is an explanation of the code, since my basic VBA-knowledge does not provide me with it.
Can someone explain what happens from "Function" and down?
Sub Opgave8()
For i = 2 To 18288
If Left(Worksheets("arab").Cells(i, 12), 6) = "262015" Then
Worksheets("arab").Cells(i, 3) = "18" & UniqueRandDigits(5)
End If
Next i
End Sub
Function UniqueRandDigits(x As Long) As String
Dim i As Long
Dim n As Integer
Dim s As String
Do
n = Int(Rnd() * 10)
If InStr(s, n) = 0 Then
s = s & n
i = i + 1
End If
Loop Until i = x + 1
UniqueRandDigits = s
End Function
n = Int(Rnd()*10) returns a value between 0 and 9, since Rnd returns a value between 0 and 1 and Int converts it to an integer, aka, a natural number.
Then If InStr(s, n) = 0 checks if the random number is already in your result: if not, it adds it using the string concatenation operator &.
This process loops (do) until i = x + 1 where x is your input argument, so you get a string of length x. Then the first part just fills rows with these random strings.
N.B. : I explained using the logical order of the code. Your friend function UniqRandDigits is defined after the "business logic", but it's the root of the code.
The code loops from row 2 to 18288 in Worksheet "arab". If first 6 characters in 12th column are "262015", then in 3rd column macro will fill cell with value "18" followed by result of function UniqueRandDigits(5) which generates 5 unique digits (0-9).
About the UniqueRandDigits function, the most important is that Rnd() returns a value lesser than 1 but greater than or equal to zero.
Int returns integer value, so Int(Rnd() * 10) will generate a random integer number from 0 to 9.
If InStr(s, n) = 0 Then makes sure than generated integer value doesn't exist in already generated digits of this number, because as the function name says, they must be unique.

Visual Basic dividing

I'm on visual basic and I'm reading through some piece of code my teacher wrote, he had this chunck of code:
Private Sub btnDividing_Click(sender As Object, e As EventArgs) Handles btnDividing.Click
Dim number As Integer = InputBox("Divide number by 2:")
Dim result As Integer = 0
Do While (number <> 0)
result += 1
number = number - 2
Loop
MsgBox("The result is: " & result, MsgBoxStyle.Exclamation)
End Sub
So my teacher typed the result += 1 and number = number -2 I didn't really understand that part so i tried simplifying it by changing it to:
Dim number As Integer = InputBox("Divide number by 2:")
Dim result As Integer = 0
Do While (number <> 0)
result = number / 2
Loop
MsgBox("The result is: " & result, MsgBoxStyle.Exclamation)
End Sub
but it keeps freezing after I click "OK"
Any suggestions?
It freezes because you made it an infinite loop:
Do While (number <> 0)
result = number / 2
Loop
The loop checks the value of number, but your modified code in the loop never modifies the value of number. So if the condition is true the first time it's checked, it will always be true. The original code modified the value:
Do While (number <> 0)
result += 1
number = number - 2
Loop
Since number is decremented by 2 with each iteration of the loop, it will eventually (assuming it's even) be equal to 0, making the loop condition false and the loop will end.
Basically, a loop needs to in some way modify the values being checked in the condition (or have some other control statement to exit the loop) or the loop will infinitely run.

Why won't the else statement run?

I am writing a function that checks to see if all elements in an array are equal, but for some reason, the else statement never seems to run, even when the if condition IS NOT TRUE. Any reason for this weird behavior? I actually displayed the result of the boolean expression a(i) = a(i + 1) and it was false. What could be going on here?
VB.NET Code:
Function EqualItems(ByVal a As Integer())
For i As Integer = 1 To a.Length - 1
If a(i) = a(i + 1) Then
If i + 1 = a.Length Then
Return True
End If
Else
Return False
End If
Next
End Function
There are more than a few things wrong here, I will explain in a bit...
First here's what I would do using Linq. Just make sure to Import System.Linq at the top of your class file...
Public Function IsEqual(ByVal a As Integer()) As Boolean
Return a IsNot Nothing AndAlso a.count > 0 AndAlso a.Distinct.Count() = 1
End Function
Breakdown of function
Make sure the array is not nothing.
We have more than one item so we can compare the other's in the array.
Finally do the compare of the items. The .Distinct.Count() = 1 will return a boolean of either True or False compare to all items that are in the array...
Note: Not good for comparing some objects this way...
Your Issue's
The first problem is this: For i As Integer = 1 To a.Length - 1. Should start at 0 for arrays. So it should look like this: For i As Integer = 0 To a.Length - 1.
The next is: If a(i) = a(i + 1) Then. This is where you would throw the IndexOutOfRange exception as because there might be not index at: a(i + 1). Solution: If Not (i + 1 = a.Length) Then check before trying to access that index...
You can declare a Boolean variable to False before everything. Then if anywhere the items are not equal return false or set the boolean to false and return that...
On a side note
Implement some Try Catch blocks to catch and handle the errors. Turn Option Strict On... If you had this on it would say something about the function may not return anything (cant remember what exactly that message is off-hand).

weird exception occurs with negative numbers

here is my code:
Dim index As Integer
do
index = find difference(board1,board2)
if index = - 1 then
exit do
end if
loop
find difference is a function that returns an integer, I have set it to return -1 if no difference is found so then the loop exits, however this gives me an outofbounds exception. i have put a try statement around the line index = find difference(board1,board2) and it catches -1 as an exception with the message:
index was out of range.
must be non-negative and less than the size of the collection.
parameter name: index.
I am at a loss as to what can be causing this, any help would be much appreciated.
EDIT:
find_difference:
dim indy as integer
dim indexes as list(of integer)
dim info as integer = 0
indexes.add(-1)
for each cell in cells
if cell.info > info then
indexes.clear
indexes.add(cell.index)
else if cell.info = info then
indexes.add(cell.index)
end if
next
indy = Math.Floor((indexes.Count + 1) * Rnd())
return indexes(indy)
end function
There is only one statement in the find_difference function which uses an index:
return indexes(indy)
Which indicates the value of indy is computed as -1 or above the size of the collection:
indy = Math.Floor((indexes.Count + 1) * Rnd())
If indexes.Count is 1 and Rnd() is greater than 0.5 then indy will be computed as 1 which would be outside the range of the collection. The + 1 should be removed.

Random numbers in array without any duplicates

I'm trying to randomize an array from numbers 0 to 51 using loops but I just cannot seem to pull it off. My idea was that
Generate a Random Number
Check if this random number has been used by storing the previous in an array
If this random number has been used, generate new random number until it is not a duplicate
If it's not a duplicate, store it
My attempt:
Dim list(51) As Integer
Dim templist(51) As Integer
For i As Integer = 0 To 51 Step 1
list(i) = i
Next i
Do While counter <= 51
p = rand.Next(0, 52)
templist(counter) = p
For n As Integer = 0 To 51 Step 1
p = rand.Next(0, 52)
If templist(n) = p Then
Do While templist(n) = p
p = rand.Next(0, 52)
Loop
templist(n) = p
Else
templist(n) = p
End If
Next
counter += 1
Loop
For n As Integer = 0 To 51 Step 1
ListBox1.Items.Add(templist(n))
Next
It will be a lot easier if you just have a list of all of the possible numbers (0 to 51 in your case), then remove the number from the list so it can't be picked again. Try something like this:
Dim allNumbers As New List (Of Integer)
Dim randomNumbers As New List (Of Integer)
Dim rand as New Random
' Fill the list of all numbers
For i As Integer = 0 To 51 Step 1
allNumbers.Add(i)
Next i
' Grab a random entry from the list of all numbers
For i As Integer = 0 To 51 Step 1
Dim selectedIndex as Integer = rand.Next(0, (allNumbers.Count - 1) )
Dim selectedNumber as Integer = allNumbers(selectedIndex)
randomNumbers.Add(selectedNumber)
allNumbers.Remove(selectedNumber)
' Might as well just add the number to ListBox1 here, too
ListBox1.Items.Add(selectedNumber)
Next i
If your goal is to get the numbers into ListBox1, then you don't even need the "randomNumbers" list.
EDIT:
If you must have an array, try something like this:
Function RandomArray(min As Integer, max As Integer) As Integer()
If min >= max Then
Throw New Exception("Min. must be less than Max.)")
End If
Dim count As Integer = (max - min)
Dim randomNumbers(count) As Integer
Dim rand As New Random()
' Since an array of integers sets every number to zero, and zero is possibly within our min/max range (0-51 here),
' we have to initialize every number in the array to something that is outside our min/max range.
If min <= 0 AndAlso max >= 0 Then
For i As Integer = 0 To count
randomNumbers(i) = (min - 1) ' Could also be max + 1
Next i
End If
Dim counter As Integer = 0
' Loop until the array has count # of elements (so counter will be equal to count + 1, since it is incremented AFTER we place a number in the array)
Do Until counter = count + 1
Dim someNumber As Integer = rand.Next(min, max + 1)
' Only add the number if it is not already in the array
If Not randomNumbers.Contains(someNumber) Then
randomNumbers(counter) = someNumber
counter += 1
End If
Loop
Return randomNumbers
End Function
This is good enough for your assignment, but the computer scientist in my hates this algorithm.
Here's why this algorithm is much less desirable. If zero is in your range of numbers, you will have to loop through the array at least 2N times (so 104+ times if you are going from 0 to 51). This is a best case scenario; the time complexity of this algorithm actually gets worse as the range of numbers scales higher. If you try running it from 0 to 100,000 for example, it will fill the first few thousand numbers very quickly, but as it goes on, it will take longer and longer to find a number that isn't already in the list. By the time you get to the last few numbers, you could potentially have randomly generated a few trillion different numbers before you find those last few numbers. If you assume an average complexity of 100000! (100,000 factorial), then the loop is going to execute almost ten to the half-a-millionth power times.
An array is more difficult to "shuffle" because it is a fixed size, so you can't really add and remove items like you can with a list or collection. What you CAN do, though, is fill the array with your numbers in order, then go through a random number of iterations where you randomly swap the positions of two numbers.
Do While counter <= 51
p = rand.Next(0, 52)
While Array.IndexOf(list, p) = -1
p = rand.Next(0, 52)
End While
counter += 1
Loop
Haven't written VB in about 5 years, but try this out:
Function GetRandomUniqueNumbersList(ByVal fromNumber As Integer, ByVal toNumber As Integer) As List(Of Integer)
If (toNumber <= fromNumber) Then
Throw New ArgumentException("toNumber must be greater than fromNumber", toNumber)
End If
Dim random As New Random
Dim randomNumbers As New HashSet(Of Integer)()
Do
randomNumbers.Add(random.Next(fromNumber, toNumber))
Loop While (randomNumbers.Count < toNumber - fromNumber)
Return randomNumbers.ToList()
End Function
Ok, that was painful. Please someone correct it if I made any mistakes. Should be very quick because it's using a HashSet.
First response to forum on stackoverflow - be gentle.
I was looking for a way to do this but couldn't find a suitable example online.
I've had a go myself and eventually got this to work:
Sub addUnique(ByRef tempList, ByVal n, ByRef s)
Dim rand = CInt(Rnd() * 15) + 1
For j = 0 To n
If tempList(j) = rand Then
s = True
End If
Next
If s = False Then
tempList(n) = rand
Else
s = False
addUnique(tempList, n, s)
End If
End Sub
Then call the sub using:
Dim values(15) As Byte
Dim valueSeen As Boolean = False
For i = 0 To 15
addUnique(values, i, valueSeen)
Next
This will randomly add the numbers 1 to 16 into an array. Each time a value is added, the previous values in the array are checked and if any of them are the same as the randomly generated value, s is set to true. If a value is not found (s=false), then the randomly generated value is added. The sub is recursively called again if s is still true at the end of the 'For' loop. Probably need 'Randomize()' in there somewhere.
Apologies if layout is a bit wobbly.