VBA code for integrating negative exponent - vba

I am trying to perform an integration using Excel VBA. Was wondering how I would do this using an approximation method if I need to integrate a negative exponent (since x/0 is undefined, hence such approximations could not estimate it)
My current code is:
Function Integral(sExp As String, dMin As Double, dMax As Double, lBit As Long)
Dim dU As Double
Dim lU As Long
dU = (dMax - dMin) / lBit
For lU = 1 To lBit
IntegralTemp = IntegralTemp + Evaluate(Replace(sExp, "u", dMin)) * dU + 0.5 * dU * Abs(Evaluate(Replace(sExp, "u", dMin + dU)) - Evaluate(Replace(sExp, "u", dMin)))
dMin = dMin + dU
Next lU
Integral = IntegralTemp
End Function

Perhaps use a Monte Carlo technique to estimate the value?
Here's a wikipedia article for this approach:
http://en.wikipedia.org/wiki/Monte_Carlo_integration

I think this is problem with function Evaluate.
I try solve this and that has managed to make:
Look on this test function:
Function EvaluateTest(str As String)
EvaluateTest = Evaluate(str)
EvaluateTest = CStr(EvaluateTest)
End Function
debug.Print EvaluateTest("0^(-0.05)") show Error 2007 i think this is dividing by zero -> 0^(-0.05) for VBA is 0/(0^0.05)
We can catch this error and for thats case accept results = 0
I create function using to catch this 1 error and modified a bit your function. Try this code:
Function EvaluateCheck(Exp As String)
Dim EvalCheck As Variant
EvalCheck = Evaluate(Exp)
If VarType(EvalCheck) = vbError Then 'evaluate function error
Select Case CInt(EvalCheck)
Case 2007 ' 0/x
'Debug.Print "Evaluate(" & Exp & ") error= " & CStr(EvalCheck); ""
EvaluateCheck = 0
'Case 2015 ' other problems with evaluate (power)
'Debug.Print "Evaluate(" & Exp & ") error= " & CStr(EvalCheck); ""
'try use power function not evaluate
'FindTmp = WorksheetFunction.Find("^", Exp)
'If FindTmp > 0 Then
'number_ = CDbl(Mid(Exp, 1, FindTmp - 1))
'Power_ = Mid(Exp, FindTmp + 1, Len(Exp))
'Power_ = Replace(Power_, ".", ",") '<- i have problems with CDbl function i must replace . to , maybe you dont need this line
'Power_ = Replace(Replace(Power_, "(", vbNullString), ")", vbNullString) ' we dont need parentheses
'PowerDbl = CDbl(Power_)
'EvaluateCheck = WorksheetFunction.power(number_, PowerDbl)
'Else
'Debug.Print "Evaluate(" & Exp & ") error= " & CStr(EvalCheck); " i cant handle that case"
'End If
Case Else
Debug.Print "Evaluate(" & Exp & ") error= " & CStr(EvalCheck); " i cant handle that case"
End Select
Else ' evaluate no error
EvaluateCheck = EvalCheck
End If
End Function
Your function:
Function Integral(sExp As String, dMin As Double, dMax As Double, lBit As Long)
Dim dU As Double
Dim lU As Long
Dim eval As Long
Dim EvaluateVal1 As Double 'Evaluate(Replace(sExp, "u", dMin))
Dim EvaluateVal2 As Double 'Evaluate(Replace(sExp, "u", dMin + dU))
Dim sExpTmp As String
dU = (dMax - dMin) / lBit
For lU = 1 To lBit
'check evaluate
sExpTmp = Replace(sExp, "u", dMin)
EvaluateVal1 = EvaluateCheck(sExpTmp)
sExpTmp = Replace(sExp, "u", dMin + dU)
EvaluateVal2 = EvaluateCheck(sExpTmp)
IntegralTemp = IntegralTemp + EvaluateVal1 * dU + 0.5 * dU * Abs(EvaluateVal1 - EvaluateVal2)
dMin = dMin + dU
Next lU
Integral = IntegralTemp
End Function
Some results:
debug.print Integral("u^(-0.05)", 0, 1, 500)
1,05186339856455
debug.print Integral("u^(-0.05)", 0.05, 1, 500)
0,991802803730478
debug.print Integral("u^(-0.05)", 0.05, 1.05, 500)
1,0417624389399

Related

How to get the Lenght of argument declarated as a variant

Function MyPV(CF As Variant, PositiveR As Double, NegativeR As Double)
Dim n
Dim i, soma
soma = 0
For i = 1 To n
If CF(i) > 0 Then
soma = soma + CF(i) / (1 + PositiveR) ^ i
ElseIf CF(i) < 0 Then
soma = soma + CF(i) / (1 + NegativeR) ^ i
Else
MyPV = "ERRO"
End If
Next i
MyPV = soma
End Function
In this code, I have to select the Cashflows and then return the present value. The book I'm using suggests doing CF as a Variant, but I can't get the value of its length. How can I do it?
I know that excel in English "," is used to separate the parameters of a function, but in Portuguese is ";"

Create Mouse Events for controls created by code

I am a beguinner in Access so I need your help with this.
I am try making a "Gannt Chart" and to do that I create some objects by code, but when I do that I can't get the atributes of the event, see
Option Compare Database
Function teste()
MsgBox ("Foi")
End Function
Function gannt()
Dim shpBox As Rectangle
DoCmd.OpenForm "Formulário3", acDesign
Set shpBox = Application.CreateControl("Formulário3", acRectangle, acDetail, "", "", 500, 500, 2000, 500)
shpBox.name = "Objeto1"
shpBox.Visible = True
shpBox.onMouseDown = "=teste()"
DoCmd.OpenForm "Formulário3", acNormal
End Function
The procedure of event has this declaration:
Private Sub Objeto1_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)
I think that one of solution is getting a mouse position by code, but I don't have a code to do this and probabily this code will bring an absolute position of the mouse.
after thinking a lot I came up with a solution.
First I had create the objects by code assigment public functions to events of MouseDown, MouseUp and MouveMove.
I've declared the public Vars
drag: The object received MouseDown Event
cod_manut: Name of the object
data_manut: Date of the start of maintenance
Option Compare Database
Option Explicit
Public drag(500) As Long
Public cod_manut(500) As Integer
Public data_manut(500, 2) As Date
Public valorX As Long '
Public valorY As Long '
Public clickX As Long '
Public clickY As Long '
Public offset As Long '
Function to populate the Form with the Gannt Objects:
Function gant()
Dim shpBox As Rectangle
Dim inicio As Integer
Dim distancia As Integer
Dim i As Integer
Dim d As Date
Dim aux As Integer
Dim entrada As Integer
Dim largura As Integer
Dim tabela As Recordset
Dim sql As String * 2048
sql = "SELECT [Programadas + status].Código, [Programadas + status].Entrada, [Programadas + status].Saida " _
& "FROM [Programadas + status] " _
& "WHERE ((([Programadas + status].Entrada) < #12/31/2020#) And (([Programadas + status].Saida) >= #1/1/2020#) And (([Programadas + status].Local) = 'SOD')) " _
& "ORDER BY [Programadas + status].Entrada, [Programadas + status].Saida;"
Set tabela = CurrentDb.OpenRecordset(sql)
i = 100
While (Not tabela.EOF)
cod_manut(i) = tabela.Fields("Código").value
d = tabela.Fields("Entrada").value
If (d < #1/1/2020#) Then
d = #1/1/2020#
End If
data_manut(i, 0) = d
d = tabela.Fields("Saida").value
If (d > #12/31/2020#) Then
d = #12/31/2020#
End If
data_manut(i, 1) = d
i = i + 1
tabela.MoveNext
Wend
DoCmd.OpenForm "Formulário4", acDesign
inicio = 1350
distancia = 408
'Set shpBox = Forms!Formulário4!Caixa0
For i = 100 To 173
aux = DateDiff("d", #1/1/2020#, data_manut(i, 0))
entrada = (aux \ 7) * 510 + (aux Mod 7) * 72
aux = DateDiff("d", data_manut(i, 0), data_manut(i, 1))
largura = aux * 72
Set shpBox = Application.CreateControl("Formulário4", acRectangle, acDetail, "", "", entrada, inicio + distancia * (i - 100), largura, 300)
shpBox.name = Replace(Str(i), " ", "")
shpBox.BackColor = 13998939
shpBox.BackStyle = 1
shpBox.Visible = True
shpBox.onMouseDown = Replace("=funcA(""" & Str(i) & """)", " ", "")
shpBox.onMouseUp = Replace("=funcB(""" & Str(i) & """)", " ", "")
shpBox.OnMouseMove = Replace("=funcC(""" & Str(i) & """)", " ", "")
Next i
DoCmd.OpenForm "Formulário4", acNormal
End Function
Function Events
Function funcA(id As String)
Dim b As Integer
Dim i As Integer
Dim nome As String
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
b = Get_Cursor_Pos()
clickX = ((valorX - offset) * 15) - Forms!Formulário4.Controls(i).Left
'clickY = (valorX - offset) * 15
drag(i) = True
End Function
Function funcB(id As String)
Dim b As Integer
Dim i As Integer
Dim nome As String
b = Get_Cursor_Pos()
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
drag(i) = False
End Function
Function funcC(id As String)
Dim aux As Integer
Dim i As Integer
Dim posX As Integer
Dim posX2 As Integer
Dim nome As String
Dim inicio As Integer
Dim fim As Integer
Dim X As Integer
Dim Y As Integer
inicio = 0
fim = 28720 - 1180
aux = Get_Cursor_Pos()
X = (valorX - offset) * 15
Y = (valorX - offset) * 15
For i = 0 To 200
nome = (Forms!Formulário4.Controls(i).name)
If nome = id Then
Exit For
End If
Next
aux = 0
If drag(i) = True Then 'And Button = acLeftButton Then
'If Shift = acShiftMask Then
posX2 = X - clickX
If Abs(posX2 - posX) > 72 Then
posX = ((posX2 - posX) \ 72) * 72 + posX + 3
posX = posX + (posX \ 504) * 6
End If
'Else
' posX = X - clickX
'End If
If posX < inicio Then
posX = inicio
ElseIf (posX + Forms!Formulário4.Controls(i).Width) > fim Then
posX = fim - Forms!Formulário4.Controls(i).Width
End If
Forms!Formulário4.Controls(i).Left = posX
Forms!Formulário4.mouse1.Caption = ((posX \ 510)) * 7 + (posX - ((posX \ 510) * 510) - 3) \ 72
Forms!Formulário4.Mouse2.Caption = (posX \ 510) + 1
End If
End Function
I had to use this code to get the absolute mouse position, but was necessary do the conversion to use this value
Note.: This value was in pixel, I need to multiply to 15 to get it in twips.
' Access the GetCursorPos function in user32.dll
Declare PtrSafe Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
' Access the GetCursorPos function in user32.dll
Declare PtrSafe Function SetCursorPos Lib "user32" (ByVal X As Long, ByVal Y As Long) As Long
' GetCursorPos requires a variable declared as a custom data type
' that will hold two integers, one for x value and one for y value
Type POINTAPI
X_Pos As Long
Y_Pos As Long
End Type
' Main routine to dimension variables, retrieve cursor position,
' and display coordinates
Function Get_Cursor_Pos()
' Dimension the variable that will hold the x and y cursor positions
Dim Hold As POINTAPI
' Place the cursor positions in variable Hold
GetCursorPos Hold
' Display the cursor position coordinates
valorX = Hold.X_Pos ' \ 15 ' Transform to twips
valorY = Hold.Y_Pos ' \ 15 ' Transform to twips
End Function
And finally I create an object with the defalt arguments of the MouseEvent to the the incremental value of the X and calculate the necessary offset to use:
Private Sub calibracao_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Dim aux As Integer
aux = Get_Cursor_Pos()
offset = valorX - (X \ 15) ' To Twips
Forms!Formulário4!mouse1.Caption = X ' Twips
Forms!Formulário4.Mouse2.Caption = (valorX - offset) * 15 ' - offset
End Sub
This was the final result:
Gannt Chart
After I drag the manut
Note: I can not make to the file available, because there are confidentially informations.
Thanks for everone that have read and probabily think about a solution, excuse me for some English mistakes.

Closest distance between lat/longs in large dataset in excel vba

Beginner looper here...I am working on this well spacing project that looks at lat/longs and determines the next closest well. I think I may be creating an infinite loop or the program is just taking forever to run (It's looping through 15,000 rows). My main struggle has been trying to make sure each location is compared to every location in the dataset. From there I take the 2nd lowest distance (since the lowest will be zero when it compares to itself).
Sub WellSpacing()
Dim r As Integer, c As Integer, L As Integer, lastrow As Integer
Dim lat1 As Double, lat2 As Double, long1 As Double, long2 As Double
Dim distance As Double, d1 As Double, d2 As Double, d3 As Double
Dim PI As Double
PI = Application.WorksheetFunction.PI()
L = 2
r = 3
c = 10
lastrow = Sheets("Test").Cells(Rows.Count, "J").End(xlUp).Row
For L = 2 To lastrow
For r = 2 To lastrow
lat1 = Sheets("Test").Cells(L, c)
long1 = Sheets("Test").Cells(L, c + 1)
lat2 = Sheets("Test").Cells(r, c)
long2 = Sheets("Test").Cells(r, c + 1)
d1 = Sin((Abs((lat2 - lat1)) * PI / 180 / 2)) ^ 2 + Cos(lat1 * PI / 180) * Cos(lat2 * PI / 180) * Sin(Abs(long2 - long1) * PI / 180 / 2) ^ 2
d2 = 2 * Application.WorksheetFunction.Atan2(Sqr(1 - d1), Sqr(d1))
d3 = 6371 * d2 * 3280.84
Sheets("Working").Cells(r - 1, c - 9) = d3
Next r
Sheet2.Activate
Range("A:A").Sort Key1:=Range("A1"), Order1:=xlAscending
distance = Sheet2.Range("A2")
Sheets("Test").Cells(L, c + 2) = distance
Sheet2.Range("A:A").Clear
Sheet1.Activate
Next L
End Sub
I've been working with geo-location math (aka, coordinate geometry) a lot lately and wrote a sub to do pretty much the same thing you're seeking.
Your code probably isn't creating an infinite loop, but calculating distances between thousands of coordinates can be very processor-intensive and even minor changes to your code can have a huge impact on processing time.
Calculating closest coordinate pair: Brute Force Method
There are a number of algorithms for determining closest points however the easiest to code (therefore possibly best for one-time use) is known as the Brute Force Method.
For p1 = 1 to numPoints
For p2 = p1 + 1 to numPoints
...calculate {distance}
...if {distance} < minDistance then minDist = {distance}
Next p2
Next p1
Using this method, distance will be calculated between x * ( n - 1 ) / 2 pairs of points.
For example, a list of 5 points would require 10 comparisons:
Point 1 ↔ Point 2
Point 1 ↔ Point 3
Point 1 ↔ Point 4
Point 1 ↔ Point 5
Point 2 ↔ Point 3
Point 2 ↔ Point 4
Point 2 ↔ Point 5
Point 3 ↔ Point 4
Point 3 ↔ Point 5
Point 4 ↔ Point 5
Since additional points will increase execution time exponentially, this method can create some lengthy processing times, especially on a slower machine or with an excessive number of points.
The methods I use for calculating distances between points and for comparing distances between lists of points are far from the [code-heavier] most-efficient alternatives, but they work for my "one-off" needs.
Depending on my purposes, I'll switch (almost identical code) between Excel & Access, but Access is much faster, so you may want to move your list into a table and do it that way.
One of the lists of points I compare has 252 items, which requires 31,628 individual comparisons using this "easy-code" method. In Excel, the process completes in 1.12 seconds, which is Access it only takes 0.16 seconds.
This may not seem like a big difference until we starting working with longer lists of points: another list of mine (closer to the size of yours) has about 12,000 points, which requires 71,994,000 calculations using the Brute Force method. In Access, the process completes in 8.6 minutes, so I estimate it would take about an hour in Excel.
Of course, all of these times are based on my operating system, processing power, Office version, etc. VBA isn't ideal for this level of computation, and everything you can do to reduce length of code will make a big difference, including commenting-out the status bar updates, immediate-window output, turn off screen updates, etc.
This code is a little messy & un-commented since I slapped it together for my own purposes, but it works for me. Let me know if you have any questions about how it works. All calculations are in metric but can be easily converted.
Sub findShortestDist_Excel()
Const colLatitude = "C" ' Col.C = Lat, Col.D = Lon
Dim pointList As Range, pointCount As Long, c As Range, _
arrCoords(), x As Long, y As Long
Dim thisDist As Double, minDist As Double, minDist_txt As String
Dim cntCurr As Long, cntTotal As Long, timerStart As Single
timerStart = Timer
Set pointList = Sheets("Stops").UsedRange.Columns(colLatitude)
pointCount = WorksheetFunction.Count(pointList.Columns(1))
'build array of numbers found in Column C/D
ReDim arrCoords(1 To 3, 1 To pointCount)
For Each c In pointList.Columns(1).Cells
If IsNumeric(c.Value) And Not IsEmpty(c.Value) Then
x = x + 1
arrCoords(1, x) = c.Value
arrCoords(2, x) = c.Offset(0, 1).Value
End If
Next c
minDist = -1
cntTotal = pointCount * (pointCount + 1) / 2
'loop through array
For x = 1 To pointCount
For y = x + 1 To pointCount
If (arrCoords(1, x) & arrCoords(2, x)) <> (arrCoords(1, y) & arrCoords(2, y)) Then
cntCurr = cntCurr + 1
thisDist = Distance(arrCoords(1, x), arrCoords(2, x), _
arrCoords(1, y), arrCoords(2, y))
'check if this distance is the smallest yet
If ((thisDist < minDist) Or (minDist = -1)) And thisDist > 0 Then
minDist = thisDist
'minDist_txt = arrCoords(1, x) & "," & arrCoords(2, x) & " -> " & arrCoords(1, y) & "," & arrCoords(2, y)
End If
'Application.StatusBar = "Calculating Distances: " & Format(cntCurr / cntTotal, "0.0%")
End If
Next y
'DoEvents
Next x
Debug.Print "Minimum distance: " & minDist_txt & " = " & minDist & " meters"
Debug.Print "(" & Round(Timer - timerStart, 2) & "sec)"
Application.StatusBar = "Finished. Minimum distance: " & minDist_txt & " = " & minDist & "m"
End Sub
Note that the procedure above is dependent on the following (which has slightly different versions for Access vs. Excel):
Excel: Calculate distance between points
Public Function Distance(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double) As Double
'returns Meters distance in Excel (straight-line)
Dim theta As Double: theta = lon1 - lon2
Dim Dist As Double: Dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) * Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta))
Dist = rad2deg(WorksheetFunction.Acos(Dist))
Distance = Dist * 60 * 1.1515 * 1.609344 * 1000
End Function
Function deg2rad(ByVal deg As Double) As Double
deg2rad = (deg * WorksheetFunction.PI / 180#)
End Function
Function rad2deg(ByVal rad As Double) As Double
rad2deg = rad / WorksheetFunction.PI * 180#
End Function
...and alternative code, for Microsoft Access:
Access: Shortest Distance
Sub findShortestDist_Access()
Const tableName = "Stops"
Dim pointCount As Long, arrCoords(), x As Long, y As Long
Dim thisDist As Double, minDist As Double
Dim cntCurr As Long, cntTotal As Long, timerStart As Single
Dim rs As Recordset
timerStart = Timer
Set rs = CurrentDb.OpenRecordset("SELECT * FROM " & tableName)
With rs
.MoveLast
.MoveFirst
pointCount = .RecordCount
'build array of numbers found in Column C/D
ReDim arrCoords(1 To 2, 1 To pointCount)
Do While Not .EOF
x = x + 1
arrCoords(1, x) = !stop_lat
arrCoords(2, x) = !stop_lon
.MoveNext
Loop
.Close
End With
minDist = -1
cntTotal = pointCount * (pointCount + 1) / 2
SysCmd acSysCmdInitMeter, "Calculating Distances:", cntTotal
'loop through array
For x = 1 To pointCount
For y = x + 1 To pointCount
cntCurr = cntCurr + 1
thisDist = Distance(arrCoords(1, x), arrCoords(2, x), _
arrCoords(1, y), arrCoords(2, y))
'check if this distance is the smallest yet
If ((thisDist < minDist) Or (minDist = -1)) And thisDist > 0 Then
minDist = thisDist
End If
SysCmd acSysCmdUpdateMeter, cntCurr
Next y
DoEvents
Next x
SysCmd acSysCmdRemoveMeter
Debug.Print "Minimum distance: " & minDist_txt & " = " & minDist & " meters"
Debug.Print "(" & Round(Timer - timerStart, 2) & "sec)"
End Sub
Note that the procedure above is dependent on the following... (Access may handle mass-calculations more quickly, but we have to build some functions ourselves that are built-in to Excel)
Access: Calculate distance between points
Const pi As Double = 3.14159265358979
Public Function Distance(ByVal lat1 As Double, ByVal lon1 As Double, _
ByVal lat2 As Double, ByVal lon2 As Double) As Double
'returns Meters distance in Access (straight-line)
Dim theta As Double: theta = lon1 - lon2
Dim dist As Double
dist = Math.Sin(deg2rad(lat1)) * Math.Sin(deg2rad(lat2)) + Math.Cos(deg2rad(lat1)) _
* Math.Cos(deg2rad(lat2)) * Math.Cos(deg2rad(theta))
dist = rad2deg(aCos(dist))
Distance = dist * 60 * 1.1515 * 1.609344 * 1000
End Function
Function deg2rad(ByVal deg As Double) As Double
deg2rad = (deg * pi / 180#)
End Function
Function rad2deg(ByVal rad As Double) As Double
rad2deg = rad / pi * 180#
End Function
Function aTan2(x As Double, y As Double) As Double
aTan2 = Atn(y / x)
End Function
Function aCos(x As Double) As Double
On Error GoTo aErr
If x = 0 Or Abs(x) = 1 Then
aCos = 0
Else
aCos = Atn(-x / Sqr(-x * x + 1)) + 2 * Atn(1)
End If
Exit Function
aErr:
aCos = 0
End Function
Planar Case
Another method of calculating closer points is called Planar Case. I haven't seen any ready-to-use code samples and I don't need it bad enough to bother coding it, but the gist of it is this:
Read about this and more about the Closest pair of points problem on Wikipedia.
I would recommend using arrays as #Qharr said. I would also look to speed up the process by including some logic steps that avoid doing the complex math on every set of points.
What I mean is that you can do a Rough Estimate first to see whether or not to bother doing the actual calculations. I went with looking at whether or not either the Lat or Long of the current position is closer than the last closest point, but you could do anything you wanted.
I would change your code to something like:
Sub WellSpacing()
Dim R As Integer, C As Integer, L As Integer, LastRow As Integer, Shortest() As Integer
Dim Lats() As Double, Longs() As Double, Distances() As Double
Dim Distance As Double, D1 As Double, D2 As Double, D3 As Double
Dim PI As Double
On Error Resume Next
PI = Application.WorksheetFunction.PI()
L = 2
R = 3
C = 10
LastRow = Sheets("Test").Cells(Rows.Count, 10).End(xlUp).Row
ReDim Lats(1 To (LastRow - 1)) As Double
ReDim Longs(1 To (LastRow - 1)) As Double
ReDim Distances(1 To (LastRow - 1)) As Double
ReDim Shortest(1 To (LastRow - 1)) As Integer
For L = 2 To LastRow
Lats(L - 1) = Sheets("Test").Range("J" & L).Value
Longs(L - 1) = Sheets("Test").Range("K" & L).Value
Next L
For L = 1 To (LastRow - 1)
'This is a method of setting an initial value that can't be obtained through the caclucations (so you will know if any calcs have been done or not).
Distances(L) = -1
For R = 1 To (LastRow - 1)
'This minimises your calculations by 15,000 to begin with
If R = L Then GoTo Skip_This_R
'This skips checking the previous distances if it is the first calculation being checked.
If Distances(L) = -1 Then GoTo Skip_Check
'If there has already been a distance calculated, this does a rough check of whether the Lat or Long is closer. If neither
'the Lat or Long are closer than the current closest, then it will skip it. This reduces the code by 7 lines for most pairs.
If Abs(Lats(L) - Lats(R)) < Abs(Lats(L) - Lats(Shortest(L))) Or Abs(Longs(L) - Longs(R)) < Abs(Longs(L) - Longs(Shortest(L))) Then
Skip_Check:
D1 = Sin((Abs((Lats(R) - Lats(L))) * PI / 180 / 2)) ^ 2 + Cos(Lats(L) * PI / 180) * Cos(Lats(R) * PI / 180) * Sin(Abs(Longs(R) - Longs(L)) * PI / 180 / 2) ^ 2
D2 = 2 * Application.WorksheetFunction.Atan2(Sqr(1 - D1), Sqr(D1))
D3 = 6371 * D2 * 3280.84
If D3 < Distances(L) Or Distances(L) = -1 Then
Distances(L) = D3
'This stores the index value in the array of the closest Lat/Long point so far.
Shortest(L) = R
End If
End If
Skip_This_R:
Next R
'This puts the resulting closest distance into the corresponding cell.
Sheets("Test").Range("L" & (L + 1)).Value = Distances(L)
'This clears any previous comments on the cell.
Sheets("Test").Range("L" & (L + 1)).Comments.Delete
'This adds a nice comment to let you know which Lat/Long position it is closest to.
Sheets("Test").Range("L" & (L + 1)).AddComment "Matched to Row " & (Shortest(L) + 1)
Next L
End Sub

How to randomize a math function/operator in visual basic (console)

This is my code so far
Module Module1
Sub Main()
Randomize()
Dim number1 As Integer
Dim number2 As Integer
Dim answer As Integer
Dim userAnswer As Integer
Dim name As String
Console.WriteLine("Hello! Welcome to your Maths Quiz! Please enter your name >")
name = Console.ReadLine
Console.WriteLine("Nice to meet you " + name + ". Lets start the quiz")
Randomize()
number1 = Rnd() * 11 + 1
number2 = Rnd() * 11 + 1
answer = number1 + number2
Try
For i As Integer = 0 To 10
Console.WriteLine("What is " & number1 & " + " & number2 & " = ?")
userAnswer = Console.ReadLine
If userAnswer = answer Then
Console.WriteLine("Correct!")
Else
Console.WriteLine("Incorrect, the answer was " & answer)
End If
Next
Catch ex As InvalidCastException
Console.WriteLine("Oops you have typed in a number, please start over")
End Try
Console.ReadKey()
End Sub
End Module
I need to create a random function to take place of the "+" sign and i have tried many ways but the output comes up weird, i was wondering if you can help, Thanks
If you are going for + - * / then I would do this, if only + - and could go with IIF statments
Create a new random variable operator
op = Int(Rnd() * 4) '0+ 1- 2* 3/
Calculate the anwser with a function
answer= calc(number1, number2, op)
Function calc(n1, n2, op)
If op = 0 Then calc = n1 + n2
If op = 1 Then calc = n1 - n2
If op = 2 Then calc = n1 * n2
If op = 3 Then calc = n1 / n2
End Function
And 1 more function to get the operator sign
Console.WriteLine("What is " & number1 & s_op(op) & number2 & " = ?")
Function s_op(op)
If op = 0 Then s_op = "+"
If op = 1 Then s_op = "-"
If op = 2 Then s_op = "*"
If op = 3 Then s_op = "/"
End Function

Calculating the median of data where some values contain "<"

I need to calculate the median of a set of measurements where in some cases a value was measured, and in some cases the value was below detection (indicated by "<" sign followed by the detection limit, e.g. <1)
Here are some examples of cases that I'm encountering:
2.0; 3.0; <1.0; 4.0 --> median = 2.5
1.0; <0.5; <0.5 --> median = <0.5
1.0; 1.0; <0.5; <0.5 --> median = <0.75
I'm a little stumped about doing this in excel VBA.
How can I do math with the values that have a "<" sign while still keeping track of the "<"?
Any input is much appreciated -- thanks!
Here's something I use:
Public Function DoAvg(rng As Range)
DoAvg = Parse(rng, "Average")
End Function
Public Function DoMedian(rng As Range)
DoMedian = Parse(rng, "Median")
End Function
'This does the work...
Private Function Parse(rng As Range, CalcType As String)
Dim rv, arr() As Single, mods As String, i As Long
Dim c As Range
Dim tmp, m
For Each c In rng.Cells
tmp = Replace(Trim(c.Value), " ", "")
If tmp Like "<*" Or tmp Like ">*" Then
m = Left(tmp, 1)
If Not InStr(mods, m) > 0 Then mods = mods & m
tmp = Right(tmp, Len(tmp) - 1)
End If
If IsNumeric(tmp) And tmp <> "" Then
i = i + 1
ReDim Preserve arr(1 To i)
arr(i) = tmp
End If
Next c
If i > 1 Then
rv = CallByName(Application.WorksheetFunction, CalcType, VbGet, arr)
Parse = IIf(mods <> "", mods, "") & rv
Else
Parse = ""
End if
End Function