Ron Rosenfeld said:
Another formula that works properly is:
evaluate("=index(indirect(""j1:j2""),1)")
or
evaluate("=index(indirect(""j1:j2""),2)")
I confirm your observation. So Evaluate does not have a problem with
INDIRECT per se.
Hmm.... Biting my tongue to avoid wild speculation about the failures of
Evaluate("...INDIRECT...").
Ron Rosenfeld said:
So how did you do this, when dealing with these formulas?
The constructs I tried using worksheetfunction returned errors.
We certainly do not want to measure WorksheetFunction time. The WF
implementation is not Excel.
Normally, I use the following paradigm. (See below for myTimer and
myElapsedTime.)
Sub test1()
Dim st As Currency, et As Currency, i As Long
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Range("e1").Clear
Range("e1").FormulaArray = _
"=sum(countifs(a1:a10000,d1:d2,b1:b10000,d3,c1:c10000,d4))"
For i = 1 To 5
st = myTimer
Range("e1").Calculate
et = myTimer
Debug.Print "time1: " & _
Format(myElapsedTime(et - st), "0.000000") & " sec"
Next
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
End Sub
Replace d1:d2 with indirect(""d1:d2"") to measure the difference that
INDIRECT makes. Not much, as I would expect.
Sometimes I use the following paradigm for a more real-life metric.
Sub test2()
Dim st As Currency, et As Currency, i As Long
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
Range("e1").Clear
Range("e1").FormulaArray = _
"=sum(countifs(a1:a10000,d1:d2,b1:b10000,d3,c1:c10000,d4))"
For i = 1 To 5
st = myTimer
Range("e1").Dirty
et = myTimer
Debug.Print "test2: " & _
Format(myElapsedTime(et - st), "0.000000") & " sec"
Next
End Sub
In either case, usually I bootstrap the number of iterations based on the
relative standard error of the 95% confidence interval around the average,
excluding "obvious" outliers. For example, for 1% rel std err, the
approximate number of iterations is n = 1.96*sd/(avg*1%) [1].
(I might throttle n back due to practical considerations.)
"Obvious" outliers are values that are many sd away from the avg. Typical
causes: (1) the first execution of code after editing; and (2) system
interrupt processing.
Caveat: Single-cell Range.Calculate or Range.Dirty might incur too much
inter-thread overhead; that is, the communication between VBA and Excel
might outweigh the execution time of the formula. Often, it is better to
set up the same formula in multiple cells, then divide the total execution
time by the number of cells. However, in doing so, there is a potential
"observer effect"; that is, increasing the number of formulas increases the
complexity of the worksheet, and that might alter Excel's behavior. The
same can be said for increasing the amount of data processed by formulas
like those above. This is the point where the scientific methodology of
performance measurement becomes more of an art.
-----
[1] 1.96 = NORMSINV(1-(1-95%)/2)
-----
Public Declare Sub Sleep Lib "kernel32" (ByVal msec As Long)
Public Declare Function QueryPerformanceFrequency Lib "kernel32" _
(ByRef freq As Currency) As Long
Public Declare Function QueryPerformanceCounter Lib "kernel32" _
(ByRef cnt As Currency) As Long
Private freq As Currency, df As Double
Function myTimer() As Currency
QueryPerformanceCounter myTimer
End Function
Function myElapsedTime(ByVal dt As Currency) As Double
If freq = 0 Then QueryPerformanceFrequency freq: df = freq
myElapsedTime = dt / df
End Function