VBA Macro Run time error 6: overflow- coding inside a loop - vba

Having a problem with this Error. I am creating a GA and the loop is to assign my fitness value to an array.
some of the variables
Dim Chromolength as integer
Chromolength = varchromolength * aVariables
Dim i as integer, j as integer, counter as integer
Dim Poparr() As Integer
Dim FitValarr() As Integer
the code:
ReDim Poparr(1 To PopSize, 1 To Chromolength)
For i = 1 To PopSize
For j = 1 To Chromolength
If Rnd < 0.5 Then
Poparr(i, j) = 0
Else
Poparr(i, j) = 1
End If
Next j
Next i
For i = 1 To PopSize
j = 1
counter = Chromolength
Do While counter > 0
FitValarr(i) = FitValarr(i) + Poparr(i, counter) * 2 ^ (j - 1)
j = j + 1
counter = counter - 1
Loop
Next i
I am having problems with:
FitValarr(i) = FitValarr(i) + Poparr(i, counter) * 2 ^ (j - 1)
I apologize, I am fairly new to VBA.

An overflow condition arises when you create an integer expression that evaluates to a value larger than can be expressed in a 16-bit signed integer. Given the expression, either the contents of FitValarr(i), or the expression 2^(j-1) could be overflowing. Suggest all the the variables presently declared as Int be changed to Long. Long integers are 32-bit signed values and provide a correspondingly larger range of possible values.

I had the same run time error 6. After much investigation l discovered that mine was a simple 'divide by zero' error.

I set up an integer value to hold Zip codes, and Error 6 events plagued me - until I realized that a zip code of 85338 exceeded the capacity of an int...
While I didn't think of a zip code as a "value" it was nonetheless certainly interpreted as one. I suspect the same could happen with addresses as well as other "non-numeric" numeric values. Changing the variable to a string resolved the problem.
It just didn't occur to me that a zip code was a "numeric value." Lesson learned.

Related

For i = StartIndex To 1 Step -1 (Index was outside bounds of array for ( i- 1)

how can I make a condition for my code to not to get out of range?
Dim StartIndex = TextBox1.Lines.Length - 1
For i = StartIndex To 0 Step -1
Dim strx = TextBox1.Lines(i - 1)
I mention that I also changed with For i = StartIndex To 1 Step -1, but it displays my values ​​wrong with one unit less. and I'm not sure if he wouldn't have errors like that.
basically I have to make this code work, without getting out of range. but which should work on For i = StartIndex To 0 Step -1 if anyone can confirm to me that it has no errors on For i = StartIndex To 1 Step -1 then I will leave him like that. it just shows me with one unit less what I need.
Dim strx = TextBox1.Lines(i - 1)
A couple of things:
Explicitly type your variables
Get the Lines property of the TextBox just once (outside of the loop)
Iterate from the length of the array (minus 1) to 1 instead of to 0
Dim lines() As String = TextBox1.Lines
For i As Integer = lines.Length - 1 To 1 Step -1
Dim strx As String = lines(i - 1)
Next
However, just briefly looking over your code it seems like you shouldn't iterate from the length of the array minus 1 since you're subtracting by 1 when you get the currently iterated item in the For/Next loop.

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.

Why is "Rank_Eq" breaking my loop?

I have a procedure which involves ranking values. My code (stripped down to important parts) looks like this:
Dim myArray() as variant
ReDim myArray(1 to 4, 1 to x)
for i = 1 to x
myArray(1,i) = a
myArray(2,i) = b
myArray(3,i) = c
next i
for j = 1 to x
myArray(4,j) = Application.Rank_Eq(myArray(3,j), Application.Index(myArray,3,0), 1)
next j
for k = 1 to x
myFunction(myArray(4,k))
next k
Debugging it, the for j = 1 to x loop works fine if I just return, say, the value of j or the value of myArray(3,j) but it breaks out of the loop at j=1 when I use the Application.Rank_Eq() formula.
Have I done something really stupid that I just can't see, or is this an Excel issue?
EDIT:
I tried using the following to debug:
myIndex = Application.Index(myArray,3,0)
for k = 1 to x
MsgBox myIndex(k,1)
a = Application.Rank_Eq(myIndex(1,k), editedRows, 1)
next k
This appears to run ok - i.e. each value of myIndex(k,1) is returned. However, if I add MsgBox a before next k, then it breaks. This suggests it's something to do with the value being returned by Rank_Eq, no?
Not sure it's part of the issue - but I had to access the Rank_Eq method through the WorksheetFunction object, not the Application object.
Secondly, you'll notice that this function needs a Double and a Range for the first 2 arguments. Currently you are supplying a Variant and whatever the value is from your Index() method.
Try casting the Variant to a Double like so for the first argument:
CDbl(myArray(3, j))
For the second argument, I have no idea from your question how the array gets populated so I can't guess where the Range argument needs to refer to...

LinEst function

I'm trying to teach myself some basic VBA in Excel 2010 and I've come across a problem I can't google myself out of. The objective is to create a button which when pressed, automatically does linest for me and writes the values into an array. So far, this is my code.
Private Sub CommandButton1_Click()
Dim linest As Variant
Dim linestArray(4,1) as Variant
Dim i As Integer, j as Integer
linest = Application.LinEst(Range("U49:U51"), Range("T49:T51"), True, True)
For i = 0 To 4
linestArray(i,0) = accessing values of linest variable fyrst column
Cells(68 + i, 21) = linestArray(i,0)
Next
For j = 0 To 4
linestArray(j,1) = accessing values of linest variable second column
Cells(68 + j, 22) = linestArray(j,0)
Next
End Sub
How do I access the values of variable linest so I can store them to an array and print them? Thank you.
EDIT: I figured it out. Variable linest is already an array! I feel pretty dumb. Sorry, this can be ignored.
New code:
Dim linestArray As Variant
linestArray = Application.LinEst(Range("U49:U51"), Range("T49:T51"), True, True)
For i = 0 To 4
For j = 0 To 1
Cells(68 + i, 21 + j) = linestArray(i + 1, j + 1)
Next
Next
The output of any such formula is a Variant array. So you've got that part right.
For a general approach to these Application. (use WorksheetFunction. instead, it's much faster) type functions is...
Type the function in Excel (as an array formula, Ctrl-Shift-Return, if need be)
The output is an N x M matrix of some sort (N =1 , M =1) for most cases
When you do Var = Application.Linest(xyx), the answer gets stored in Var
Get the size of the Var using Ubound(Var, 1), Ubound(Var, 2) to get number of rows and columns (note that these are base 0 type arrays)
Usually, the size will be one x one. In that case, your variable is stored in Var(0,0) i.e. a zero base multidimensional variant array, the top left element.
Hope this helps.

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.