A few questions have come up recently involving the Application.Evaluate method callable from Excel VBA. The old XLM macro language also exposes an EVALUATE() function. Both can be quite useful. Does anyone know why the evaluator that is exposed can handle general expressions, though?
My own hunch is that Excel needed to give people a way to get ranges from string addresses, and to get the value of named formulas, and just opening a portal to the expression evaluator was the easiest way. (The help for the VBA version does say its purpose it to "convert a Microsoft Excel name to an object or a value".) But of course you don't need the ability to evaluate arbitrary expressions just to do that. (That is, Excel could provide a Name.Evaluate method or something instead.)
Application.Evaluate seems kind of...unfinished. It's full behavior isn't very well documented, and there are quite a few quirks and limitations (as described by Charles Williams here: http://www.decisionmodels.com/calcsecretsh.htm) with what is exposed.
I suppose the answer could be simply "why not expose it?", but I'd be interested to know what design decisions led to this feature taking the form that it does. Failing that, I'd be interested to hear other hunches.
Well I think its required to enable VBA to get the result from a Named Formula (or a string containing a formula), (OK there is also the ugly method of inserting the formula into a spare cell and then reading back the result, but for example that won't work from inside a UDF).
In VBA its complex to determine if a Defined Name contains a range reference or a formula. Using Evaluate works for both cases.
Its also sometimes very efficient and simpler to build Excel formulae as strings and evaluate them rather than having to bring all the data from Excel into VBA and then do the calculations in VBA. (Its expensive to get data from Excel into VBA and even worse with current .NET implementations).
Related
let's suppose I write the following VBA UDF:
Function TestFunction()
TestFunction = 0
End Function
and then I use it for the first 100000 rows in my sheet. It takes several minutes to execute.
Instead if i use TODAY() for the same number of rows it takes just 3-4 seconds to execute.
Can anyone tell me why and if is there a way to speed up UDFs?
Thank you!
Several reasons.
VBA functions need to run sequentially, off the UI/main thread, and the compiled p-code needs to be interpreted by the VBA runtime.
Native functions are native. They're (presumably - AFAIK they're written in C++) already compiled to machine code that's readily executable and doesn't need to be recompiled and/or interpreted. Some native functions can also leverage multithreaded and "background" computing.
As for speeding up your UDFs, we'd need to see your UDFs for that. A function that does nothing other than assigning a literal return value, doesn't have much room for optimization does it?
UDFs are great. But they're not a silver bullet. If I wanted to write the value 0 to A1:A1000000, I'd do Sheet1.Range("A1:A1000000").Value = 0 and that would be near-instant.
Consider looking into macros rather than UDFs if you're going to have hundreds of thousands of them to calculate.
There are a number of different reasons for this.
For one VBA UDFs are interpreted whereas native Excel worksheet functions are compiled. You would get big speed increases if you compiled your VBA code as VB6 for example. VBA and VB6 code are either the same or almost exactly the same. So the reason for the big speed increase would just be that the VB6 code is compiled rather than interpreted like VBA code is.
VBA code also doesn't produce the same type of worksheet functions that Excel does. VBA UDFs lack worksheet intellisense for example. You can't get this in any way through VBA. You can get it through external add-ins elsewhere however (e.g. Excel DNA.)
Another reason is that VBA isn't the best API for writing performant UDFs. That would be the C API. But the C API is harder to write UDFs in than in VBA.
There are also a number of other things that could affect speed, like your underlying hardware, or the algorithm you're using in the UDF. It's hard to give you useful suggestions without seeing your code.
Are you sure you need UDFs? The only advantages UDFs have over macros (that I'm aware of anyway) is that they don't delete the undostack after they're called whereas most macros do. And they can recalculate dynamically whereas you continuously have to rerun macros after they're called (unless you're using a worksheet event or something.)
If you're doing a ton of calculations on a range of cells, it's probably better to just write the range to an array, manipulate it in VBA, and then just write it back to the range.
Is there a way to assess a speed comparison between UDFs, User-Defined-Functions, and Excel's built in functions without benchmark testing? A purely mathematical approach if you will.
For instance, I recently posted the following question:
Unique Count (Excel VBA vs Formulas) Faster Approach
After writing the UDF it was obvious that it was much faster, but I frankly assumed it wouldn't have been, and am looking for clarity on how I can better align my judgement BEFORE writing vba that proves useless.
I found this:
Speed, VBA VS Excel Formulas , but their question wasn't exactly the same as mine.
I doubt an Excel spreadsheet can handle this but it's worth asking, since I have been trying and searching for a long time with no success.
Entering this into a cell:
=complex(abs(-1.5*(-1.5)^(-1.5))),0)
and the cell output is #NUM!
The output should be: 0.8164966
I played with this a bit and didn't get anywhere - this article may explain why.
Link
it's complicated, and I think it's more than an excel problem
The following pdf has a nice write-up for using complex number functions in excel.
https://ccnet.stanford.edu/cgi-bin/course.cgi?cc=ee246&action=handout_download&handout_id=ID11300955936304
Seems like you have made a mistake inserting the parentheses.
The correct form is:
=COMPLEX(ABS((-1.5)*((1.5)^(-1.5))),0)
=0.816496580927726
This runs well in Excel 2013.
I want to print a row in Excel.
One row contains data for one project.
I want to print one row on one page nicely formatted. Meaning the value of one cell is the header and should be printed fat and centred, the other values should also be placed at fixed positions on the page.
Is this with VBA possible? When I was searching for this problem I only found results for printing a worksheet or a table or parts of it, but no results to use the values of the cells and formatting them.
Thanks in advance
As the other answers indicate, it is certainly possible in Excel VBA, but it is not really Excel's strong point.
What would typically be done to obtain the result you seem to be after is use a fully formatted Word document with fields that are then filled in with values from an Excel worksheet. You can even cheat a bit and use the Mail Merge \ Letter wizard to set everything up.
If you do want to do it all in Excel, you can find instructions and an example VBA macro here:
http://www.tek-tips.com/faqs.cfm?fid=4223
Template is a good way to do. With a macro there's better performance where it avoids the usage of volatile functions such as INDIRECT() However again it depends on how many volatile functions your worksheet carries.
Yes, it is possible when you use the Styles in excel. I know you can do Font formatting quite easily. Not sure about indenting it, but worth a try.
If style doesnt support it (it might in Excel 2010), you can always indent it via VBA (record a macro when you indent the values , it should look like this):
Selection.InsertIndent 1
I need to have a capability to execute any kind of build-in functions (such as 'sum' or 'len') from VBA (MS Excel).
One of the restrictions that I have is that I may not pass cell ranges as arguments to these functions. Instead of this, I should be able to use strict values.
I want to be able to use the following expression SUM(1, 2) which should return 3, while the following version SUM("A1:A2") won't work for me.
I managed to develop some function that parses my prior input and makes it consist of a list of values (as for example above, it made the user's input of 'A1:A2' look like an array of numbers consisting of two values).
So, can anyone give me an example of using a build-in function that receives a list of values (not just range of cells)?
I tried the following code, but for some unknown reason, I haven't been able to get it working (I keep getting 1004 error, saying: Cannot run the macro 'SUM'. The macro may not be available in this workbook or all macros may be disabled.):
Application.Run "SUM", 2, 2
Some valuable advices that would help to find a solution to this problem will be greatly appreciated.
To use a built-in, Excel, Worksheet function, you need to do something like the following:
Application.WorksheetFunction.Sum(2,2)