Set Long Variable in VBA - vba

Simple question that I can't find anywhere. When I'm doing arithmetic, it seems the natural type is to treat value as 16Bit Integers.
I'm trying to save the result of 60 * 60 * 8 * 5 into a long, but I get an Overflow error before it even has a chance to save the number as a Long:
Dim secondsInAWorkWeek As Long
secondsInAWorkWeek = 60 * 60 * 8 * 5
Long should happily store anything up to 231 = 2,147,483,647
How can I perform the multiplication safely to convert into a long

There are certain conventions in order to force a literal to a specific type from a generic (default) type: http://msdn.microsoft.com/en-us/library/dzy06xhf.aspx
Which leads to this code:
Dim secondsInAWorkWeek As Long
Let secondsInAWorkWeek = 60& * 60& * 8& * 5&
or:
Const DAYS_IN_WEEK = 5&
Const HOURS_IN_DAY = 8&
Const MINUTES_IN_HOUR = 60&
Const SECONDS_IN_MINUTE = 60&
Dim secondsInAWorkWeek As Long
Let secondsInAWorkWeek = _
DAYS_IN_WEEK _
* HOURS_IN_DAY _
* MINUTES_IN_HOUR _
* SECONDS_IN_MINUTE
A lot more to write, true, but is type safe, barely needs any more explanations/comments, and it will be easy to change when they'll vote for 10 hours workdays. :-)

Ok, according to Overflow when multiplying Integers and assigning to Long, you need to give Excel a running start, otherwise it will default each value in the multiplication to an integer.
Just start off by casting to long with CLng and it will take care of the rest:
Dim secondsInAWorkWeek As Long
secondsInAWorkWeek = CLng(1) * 60 * 60 * 8 * 5

Related

TextBox to TextBox Calculations

Maybe a simple question but I still need some help with a formula clarification:
Could somebody help me with this:
TempCalc = CInt(TextBox3.Value) * (16*POWER(SQRT(CInt(TextBox1.Value)*(1-CInt(Textbox1.Value)))/(CInt(TextBox1.Value)*CInt(TextBox2.Value);2))
what is wrong, is the syntax totally off?
Thanks in advance
The function POWER and SQRT do not exist in VBA.
Power(x, y) can be replaced with x ^ y
sqrt is sqr in VBA
So the following should work:
TempCalc = CLng(TextBox3.Value) * (16 * ((Sqr(CLng(TextBox1.Value) * 1 - CLng(TextBox1.Value))) / (CLng(TextBox1.Value) * CLng(TextBox2.Value))) ^ 2)
And I recommend to convert the integers to Long using CLng as there is no benefit in using Integer.
So to make it easier to debug I recommend to split the calculation:
Dim SqrtVal As Double
SqrtVal = Sqr(CLng(TextBox1.Value) * 1 - CLng(TextBox1.Value))
Dim DivVal As Double
DivVal = (CLng(TextBox1.Value) * CLng(TextBox2.Value))
Dim PowerVal As Double
PowerVal = (SqrtVal / DivVal) ^ 2
Dim TempCalc As Double
TempCalc = CLng(TextBox3.Value) * 16 * PowerVal

Is there a way to avoid the error statement "Arithmetic operation resulted in an overflow."?

I've done some research and the general advice is changing the datatype of the variable holding the expression to Long or Ulong but in either case, I'm still getting the same error. I also tried enclosing the expression with CInt() (or CLong()) to force it to cut out it's decimal portion to reduce the length of the output of the expression but neither is working. It's all pretty confusing. Any help will be deeply appreciated. The code block triggering the error is as follows;
Vsf(i) = CInt((((0.91544 - 0.00166 * Angle(i) - 0.000002 * W - 0.054248 *
Superelevation(i) - Sidefrictionfactor) / 0.013939) * Radius(i)) ^ 0.5)
Vro(i) = CInt((((1.04136 - 0.004528 * Angle(i) - 0.000004 * W - 0.338711 * Superelevation(i) - rolloverthreshold) / 0.014578) * Radius(i)) ^ 0.5)
Vmin(i) = CInt(Math.Min(Vsf(i), Vro(i)))
I declared VSf(), Vro() and Vmin() all as integer arrays. I even enclosed the computation expression in a CInt() in hopes that it would convert the result of Vro (which was triggering the arithmetic overflow error) to an integer and hence not have to deal with decimals which would lead to more digits. Yet when I hover over Vro(i), I see a 4 digit integer with decimals. Not sure why that's happening.
I broke the formula down to try and see where the problem was occurring. Everything buzzed along until the very end. If the value to be raised to .5 is a negative number, the square root does not produce a number. I would perform the steps of the formula without the ^.5 and then check for a negative number.
Private Sub OPCode()
Dim Angle = 90.2
Dim Radius = 100.2
Dim Superelevation = 37.8
Dim Sidefrictionfactor = 0.003
Dim W = 0.00325
Dim Vsf As Double
Dim AngleMultiplication = 0.00166 * Angle
Dim WMultiplication = 0.000002 * W
Dim SuperelavationMultiplication = 0.054248 * Superelevation
Dim SubtractResult = 0.91544 - AngleMultiplication - WMultiplication - SuperelavationMultiplication - Sidefrictionfactor
Dim DivisionResult = SubtractResult / 0.013939
Dim MultiplyByRadius = DivisionResult * Radius
Debug.Print(MultiplyByRadius.ToString) 'With my made up values I get a negative number
Vsf = MultiplyByRadius ^ 0.5 'You cannot get the square root of a negative number
Debug.Print(Vsf.ToString) 'NaN
Dim intVsf = CInt(Vsf) 'The Arithematic overflow error occurs here
End Sub

Need help getting my points per hour function to work properly

I'm having difficulty getting my function to work right.
This function is supposed to estimate how many points per hour the user would get but instead it shows way too many numbers.
Dim now As DateTime = DateTime.Now
Private Function PointsPerHour(gainedpoints As String, totalpoints As String)
Dim firstvalue = gainedpoints
Dim secondvalue = firstvalue
Dim thirdvalue = totalpoints
Dim varJWG0 As String = "Points: "
Dim varJWG1 As String = thirdvalue
Dim varJWG2 As String = " Points Per Hour: "
Dim varJJM0 As Double = Double.Parse(thirdvalue.Replace(",", String.Empty)) - Double.Parse(secondvalue.Replace(",", String.Empty))
Dim timeSpan As TimeSpan = Now - DateTime.Now.ToLocalTime
Dim dbl_ As Double = varJJM0 / timeSpan.TotalHours * -1.0
Return (Convert.ToString(varJWG0 & varJWG1) & varJWG2) + dbl_.ToString("0.00")
End Function
Even if I do PointsPerHour(9, 91) it still outputs more than 1000.
What am I doing wrong?
So I am not entirely certain what it is that this method is trying to achieve in your current implementation.
Firstly the values firstValue and secondValue are the same, also firstValue does not seem to be used apart from assigning to secondValue, which just seems redundant to me.
The first problem I can see is that you have no time in this function. The timeSpan you are using to hold presumably the totalHours is not holding a useful value. you are subtracting Now from Now.ToLocalTime. You will either get 0 or your timezone offset from this equation.
Basically; assuming your 9, 91 example; you are getting ((91-9)/timeSpan) * -1).
If 9 is the points you are earning per hour, and 91 is total points, then 91/9 = hours. or if you give the hours 9 * hours = 91 (in this case 10.1).

How to get the count of digits after the comma of a double-number in VB.NET?

Examples:
Double-Number is 56.6789 result should be 4
Double-Number is 12345.67 result should be 2
Double-Number is 12345.6 result should be 1
I have a solution tinkering with strings, but I think there is an mathematical solution?
Please in VB.NET ...
Split the original number and get the length of the upper index (1)
myNumber = 12.3456
Dim count As Integer = Len(Split(CStr(myNumber), Application.DecimalSeparator)(1))
Debug.Print count // prints '4'
edit: replaced "." with decimal separator to ensure use across varying cultures
You can try like this:
Dim x As String = CStr(56.6789)
Dim count = x.Length - InStr(x, ".")
One way to do it is to keep knocking off the whole part, multiplying by 10, repeat until you have an integer:
Dim x As Double = 1.23456
Dim count As Integer = 0
While Math.Floor(x) <> x
x = (x - Math.Floor(x)) * 10D
count = count + 1
End While
Note this will fail if there is an infinite number of decimal places - so you could set a limit on it (If count > 100 Then Exit While)
Another way would be like this, which converts to a string but removes the need to hardcode the separator.
Dim x As Double = 1.23456
Dim x0 As Double = x - Math.Floor(x)
Dim x0String As String = x0.ToString()
Dim count As Integer = x0String.Substring(2, x0String.Length - 2).Length
Using Application.DecimalSeparator also allows a string to be used.
The method with a string will again lose information about an infinite-length fractional part, as it will truncate it.

VBA convert time

I need to convert time from 14:54 to a double 14+54/60. And i do this with the following code:
Private Function Omzetten(ByVal time As String) As Double
Dim min As Integer, hours As Integer, datum As Date
datum = CDate(time)
min = DatePart("n", datum)
hours = DatePart("h", datum)
Omzetten = hours + min / 60
End Function
But when the time is 26:00 he only gives 2 because 26-24 is 2. So I thought to ad day = DatePart("d", datum), but then he always gives day = 30. Does anyone has a solution?
if its always in the format hours : mins then use the below:
Dim str As String
Dim strSplit() As String
Dim Val As Double
str = "26:00"
strSplit = Split(str, ":")
Val = CInt(strSplit(0)) + CInt(strSplit(1)) / 60
Try the following, I used VB.Net which from above looks like it must be compatible with the newer VBA variants:
Private Function Omzetten(ByVal time As String) As Double
Dim Hours As Integer = CInt(time.Substring(0, time.IndexOf(":")))
Dim Minutes As Integer = CInt(time.Substring(time.IndexOf(":") + 1))
Return Hours + Minutes / 60
End Function
Just as a note you might want to add some extra checks, the above code will for example fail on non-numeric input or if the time doesn't contain a colon. You might want something more like the following to cope with varying inputs:
Private Function Omzetten(ByVal time As String) As Double
Dim Hours As Integer = 0
Dim Minutes As Integer = 0
Dim HoursStr As String
If time.IndexOf(":") = -1 Then
HoursStr = time
Else
HoursStr = time.Substring(0, time.IndexOf(":"))
End If
If IsNumeric(HoursStr) Then
Hours = CInt(HoursStr)
End If
If time.IndexOf(":") >= 0 Then
Dim MinutesStr As String = time.Substring(time.IndexOf(":") + 1)
If IsNumeric(MinutesStr) Then
Minutes = CInt(MinutesStr)
End If
End If
Return Hours + Minutes / 60
End Function
I think you can achieve this with basic Excel formulas.
As times are stored as numbers if you divide any time by 1/24 (i.e. an hour) you'll get the answer as a double.
Note - if you want to use times over 24 hrs (e.g. 26:00) then set the cell custom format to [h]:mm:ss
Examples
A B
1 14:54 =A1/(1/24) // = 14.9
2 26:00 =A1/(1/24) // = 26.0
Does this help?