How to fine the range of a number? - vba

The valid range of a Byte variable is 0 and 255.
Dim b As Byte
b = 30
' The following statement causes an error because the value is too large.
'b = 256
how to find the range of a number like 30 = 256

I may be misunderstanding your question, but have you looked at the documentation for data types? http://msdn.microsoft.com/en-us/library/vstudio/47zceaw7%28v=vs.120%29.aspx
The documentation explicitly states the valid ranges for all data types.

Related

Where the type mismatch error 13 comes from in this case?

One of my Excel worksheets contains many data and the cells are in number format. (for instance it is filled with numbers like 1,02458)
In another worksheet I am trying to do some calculus based on the first worksheet, and for this I am using VBA code:
Dim sum, price, strike As Double
sum= 0
strike = 0.02
For k = 1 To 5000
sum= sum+ Worksheets("Feuille1").Cells(k, 7).Value - strike
Next k
When I try to run this the line with the sum corresponds to the error 13 type mismatch.
I have tried things such as changing the cell format, and even using Variant instead of Double but it changed nothing. How to avoid the type mismatch ?
Is there a header in Sheet "Feuille1" range "G1"?
In that case you're trying to add a string to the sum, which will lead to type mismatch. If the digits start at row 2, then change your loop to
For k = 2 to 5000

Overflow Error evaluating arithmetic expression with integers in VBA

The following evaluates to 32760, an integer:
Debug.Print (20 * 1638 - 1)
But this raises an overflow error:
Dim t as Integer
t = 1639
Debug.Print (20 * t - 1)
It seems like this is implicitly expecting an Integer return value, because if I do either of the following, the error is avoided.
Dim t as Long OR Debug.print (20 * CLng(t) - 1) OR Debug.Print (20# * t - 1)
Is this behavior documented?
Is my assumption accurate? Namely, that arithmetic of integers implies an integer return value, and that simply introducing one Long or Double value in to the equation will avoid the error?
If my logic is correct, Dim or 'Dimension' is a way of telling the application that you expect use a variable of a certain type, and that type pertains to a certain amount of 'bits' (of memory).
This reserves a section of the system's memory, which has been allocated a certain amount of bits dependant on the variable type that you have instructed in your code. These bits then define how many (If you're familiar with C++ or similar then you will probably already know all this...)
An Integer is 16 bits in VBA and is a signed integer which means we can store negative values too, so the limit is 32,767 because this is the biggest number we can achieve with 16 bits:
(generally a variable can hold 2^n where n = number of bits)
unsigned 16 bits = 0 - 65,536 (2^16)
signed 16 bits = -32,768 - 32,767
32,767 = 111111111111111 (Binary)
32,768 = 1000000000000000 <--- note the extra bit
This extra bit is what causes the "overflow" error - because the amount of bits required to produce the number overflows the amount of bits that the memory has to store the number safely.
I don't think the method of the calculation is documented to this extent, however your code snippet:
Dim t as Integer
t = 1639
Debug.Print (20 * t - 1)
would require t to be first be multiplied by 20, resulting in a figure of 32,780:
20 * t = 20 * 1639 = 32,780
32,780 = 1000000000001100 (Binary)
which overflows the bit limit for the Integer data type. At this point the system throws an error before it has the chance to proceed with the rest of the calculation because it tries to multiply t whilst still in it's allocated memory address, for which only 16 bits of memory have been reserved.
Also, not declaring t as a type will force VBA to default to type Variant which will assess that t needs to have more memory allocated when the calculation runs and push it into the Long boundary automatically.
Update: It would appear that VBA will only permit the highest amount of bits held by a variable within the equation for the return value, as can be seen in this example:
Sub SO()
Dim t As Integer, c As Long
t = 1639
c = 20
Debug.Print (20 * (t - 1)) '// No Error
Debug.Print (c * (t - 1)) '// No Error
Debug.Print ((c * t) - 1) '// No Error
c = (20 * t - 1) '// Error
Debug.Print (20 * t - 1) '// Error
End Sub
Although I don't believe this is documented anywhere, it would lead one to believe that VBA limits memory usage to the highest amount of bits being used by a variable at any one time.

VBA overflow error with byte variables

Can someone please explain why the following code would generate an overflow error in VBA when the recipient of the operation c is an Integer?
Dim a As byte, b As Byte
Dim c As Integer
a = 3: b = 100
c = a * b
or does it mean that every operation involving 'Byte` variables would have to yield only a result be between 0 and 255 regardless of the recipient variable type?
or does it mean that every operation involving byte variables would have to yield only a result be between 0 and 255 regardless of the recipient variable type
Yes, because Bytes only hold values from 0 to 255, multiplying 3 x 100, you are passing (overflowing) its capacity, even though afterwards you are passing the result into an integer.
Because you are multiplying two Bytes together, VBA assumes the result to be a Byte too. It is only after the calculation that the result is then cast to an integer.
To get around this, you must cast at least one of the variables. This lets VBA know that it must make room for a larger result:
Dim a As Byte, b As Byte
Dim c As Integer
a = 3
b = 100
c = a * CInt(b) ' <-- Cast b as Integer to prevent Overflow error

#VALUE error with Excel VBA Function

In my Excel spreadsheet I have two columns.
A contains strings with the values 'Yes', 'No' or 'Maybe'.
B contains strings with a year in.
I need a function to determine the number of occurrences of a year in column B, where the equivalent value in column A is 'Yes'.
I currently have the following code:
Function CountIfYearAndValue(Rng As Range, YNM As String, Year As String) As Integer
Dim count As Integer
count = 0
For Each c In Rng.Cells
If (StrComp(Abs(c.Value), Year, vbTextCompare) = 0) And (StrComp(Cells(c.Row, A), YMN, vbTextCompare) = 0) Then count = count + 1
Next
CountIfYearAndValue = count
End Function
The idea of this code is that we iterate through every cell in the range given (a range on column B) and check if the year is equal to the Year parameter. And if the equivalent cell on column A is equal to the YNM parameter we increment the count variable.
For some reason this code does not work when I use the following parameter:
=CountIfYearAndValue('Years'!B1:B7,"Yes","Year 7")
It just does the #VALUE error and refuses to display any outcome.
Any help would be much appreciated.
Edit: All of the values in both cells are on of an unformatted datatype ('General') and no cells are blank.
It sounds like you are reinventing the wheel... There already is a built in function (advantage: being much faster than a UDF) that does exactly what you are after. It is called COUNTIFS()
All YESes for Year 7 in rows 1 to 10.
=COUNTIFS(B1:B10, "Year 7",A1:A10, "Yes")
I just had a quick look at your code and I think there are possibly a few reasons why your original code is not working as expected.
YNM is a valid column name therefore it should not be used as a variable name. You should avoid naming your variables like that - give it a more meaningful name
YNM != YMN as you had it in your code (see function definition and then the misspelled version in the StrComp() function)
Year is a valid VBA built in function, therefore once again you should avoid using it as a variable name as you're exposing yourself to a naming collision.
Add Option Explicit at the top of your module. This requires you to Dimension all you variables. It's always recommended for many many reasons.
rng variable is of Range type therefore you do not need to explicitly add the .Cells property to it. Even though it may help in some cases - at a bit more advanced level you may face some runtime type compatibility issues. ( runtime may convert your rng Range variable to a 2D array etc )
Added an explicit conversion in the second StrComp() function around the c.Offset(0, -1) as you don't want the runtime to (rare but still possible) convert your Yes to a Boolean data type. Explicit conversion to a String just gives you that extra protection ;p (lol)
therefore, something like this returns the correct value
Function CountIfYearAndValue(rng As Range, choice As String, myYear As String) As Long
Dim count As Long
count = 0
Dim c As Range
For Each c In rng
If (StrComp(c, myYear, vbTextCompare) = 0) And (StrComp(CStr(c.Offset(0, -1)), choice, vbTextCompare) = 0) Then
count = count + 1
End If
Next c
CountIfYearAndValue = count
End Function
Right, I hope this helps you understand bits and pieces :) any questions please leave a comment

Overflow when multiplying Integers and assigning to Long

If I type the following into the immediate window I get Runtime error '6': Overflow.
MsgBox 24 * 60 * 60
Why is this?
This also fails:
Dim giveTime As Long
giveTime = 24 * 60 * 60
Why is this? giveTime is declared as a Long type, so 24 × 60 × 60 = 86400 should comfortably fit.
This is a really odd VBA quirk. I'm amazed I've never bumped into this.
Dim x As Long
x = 24 * 60 * 60 ' Overflow
x = 32767 + 1 ' Overflow.
x = 32768 + 1 ' Works fine!
So it looks like the * and + operators return an Integer in the first two examples. Sure enough, in the help file for the *operator (similar for the + operator):
result = number1 * number2
[...]
The data type of result is usually the same as that of the most precise expression.
Your literals 24, 60, and 60 are all of type Integer by default, so your * (or +) operator returns an Integer, which overflows because the result is greater than 32,767.
However, the literal 32,768 in the third example above defaults to Long type (since it is too large to be an Integer) and so the + returns a Long; no overflow.
The help file also says this:
If [...] the data type of result is an Integer variant that overflows its legal range [...] Then result is [...] converted to a Long variant.
Emphasis mine. Now this little rule sounds like common sense, and anyone would reasonably assume that it applies in your case. But your numbers are of type Integer, not Variant/Integer, so VBA doesn't apply this rule! Makes absolutely no sense to me, but that's how it is, and that's what the documentation says.
Solution: make one of the arguments of your * operator be of a type more precise than Integer (e.g. Long) and the problem will go away.
x = CLng(24) * 60 * 60 ' Result is Long, works fine.
In fact, and this is probably why I've never bumped into this quirk, I make a habit of declaring all of my Integer variables as Long instead, unless there is a specific concern that having Longs instead of Integers will cause problems with memory use or execution time (which is almost never the case). Granted, this won't help in cases when you operate on literals smaller than 32,768, because they default to Integer type.
You ask in a comment what a Variant/Integer is. Variant is basically a container type for any other data type. In the particular case where you make it contain an Integer:
Dim a As Variant ' a is now Empty
a = CInt(32767) ' a is now Variant/Integer
x = a + 1 ' works fine
But as noted above, a plain old Integer triggers the overflow error:
Dim b As Integer
b = 32767
x = b + 1 ' overflow
After every number, place #. It defines each number as a double. Think of it as, each number is placed in to memory for the calculation as sort of a temp variable.
If you define each number, it will allow enough space for the calculations.
eg:
Dim x As Long
x = 24# * 60# * 60#
or 24& 'indicates long