<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Excel and UDF Performance Stuff</title>
	<atom:link href="http://fastexcel.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://fastexcel.wordpress.com</link>
	<description>Charles Williams on &#039;Making Excel go Faster&#039;</description>
	<lastBuildDate>Tue, 21 Feb 2012 14:25:36 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='fastexcel.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://1.gravatar.com/blavatar/9c4d2a0518651185516d83edc87c201a?s=96&#038;d=http%3A%2F%2Fs2.wp.com%2Fi%2Fbuttonw-com.png</url>
		<title>Excel and UDF Performance Stuff</title>
		<link>http://fastexcel.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://fastexcel.wordpress.com/osd.xml" title="Excel and UDF Performance Stuff" />
	<atom:link rel='hub' href='http://fastexcel.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Writing efficient VBA UDFs Part 10 &#8211; Volatile Functions and Function Arguments</title>
		<link>http://fastexcel.wordpress.com/2012/02/02/writing-efficient-vba-udfs-part-10-volatile-functions-and-function-arguments/</link>
		<comments>http://fastexcel.wordpress.com/2012/02/02/writing-efficient-vba-udfs-part-10-volatile-functions-and-function-arguments/#comments</comments>
		<pubDate>Thu, 02 Feb 2012 12:35:24 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Calculation]]></category>
		<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=319</guid>
		<description><![CDATA[I just realised that none of my previous 9 posts on writing efficient VBA UDFs has discussed when and why you should make Functions Volatile. Since that&#8217;s fairly fundamental I really should have covered the topic early in the series &#8230; but anyway here goes. What does Volatile mean? Normally Excel&#8217;s smart recalculation engine only [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=319&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I just realised that none of my previous 9 posts on writing efficient VBA UDFs has discussed when and why you should make Functions Volatile. Since that&#8217;s fairly fundamental I really should have covered the topic early in the series &#8230; but anyway here goes.</p>
<h3>What does Volatile mean?</h3>
<p>Normally Excel&#8217;s smart recalculation engine only recalculates formulas that either have been changed/entered or depend on a cell or formula that has been changed somewhere higher up the chain of precedents for the formula.</p>
<p>This makes for very efficient calculation speed since in a typical workbook only a small faction of the formulas will be dependent on any particular cell or piece of data.</p>
<p>But some functions need to recalculate at every recalculation. For example NOW() should always give you the current time at the last calculation, and RAND() should give you a different random number each time it is calculated. These functions are called Volatile Functions, and any formula that uses one of them is a Volatile formula.</p>
<p>You can see more discussion of Excel&#8217;s built-in volatile functions and the volatile actions that trigger a recalculation at <a href="http://www.decisionmodels.com/calcsecretsi.htm">http://www.decisionmodels.com/calcsecretsi.htm</a>.</p>
<h3>How does Excel&#8217;s smart recalc engine know when to recalculate a function or a formula?</h3>
<p>Excel maintains its dependency trees by looking at what other cells a function or a formula refers to, and the smart recalc engine uses these dependency trees to work out which formulas to recalculate.</p>
<p>For Functions Excel only looks at the arguments to the function to determine what the function depends on. So if you write a function like this:</p>
<p><code><br />
Function Depends(theCell as range)<br />
Depends=ActiveSheet.range("Z9")+theCell + _<br />
theCell.Offset(0,1)<br />
End Function<br />
</code><br />
and call it in a formula =Depends(&#8220;A1&#8243;)<br />
<strong>then Excel will only recalculate your function when A1 changes, and not when B1 or Z9 changes.</strong></p>
<p>This could give you incorrect results.</p>
<p>Note: During a recalculation if Excel <strong>does</strong> evaluate the UDF it determines which cell references are actually being used inside the function to affect the function result, and if those cells have not yet been finally calculated it will reschedule the Function for later calculation. This is required to make the UDF be finally calculated in the correct dependency sequence.</p>
<h2>How to fix this problem</h2>
<p>There are several ways to fix this problem, but only one good one!</p>
<h3>Make the function Volatile</h3>
<p>If you add Application.Volatile to the function it will always recalculate:<br />
<code><br />
Function Depends(theCell as range)<br />
<strong>Application.Volatile</strong><br />
Depends=ActiveSheet.range("Z9")+theCell+ _<br />
theCell.Offset(0,1)<br />
End Function<br />
</code><br />
But this will slow down the calculation, so generally its a bad idea unless, like RAND() or NOW() the function really needs to be Volatile.</p>
<h3>Use Ctrl/Alt/F9 to trigger a full calculation</h3>
<p>If you press Ctrl/Alt/F9 then Excel will recalculate every single formula in all the open workbooks, regardless of what has changed or is volatile.<br />
Of course this can be very slow.</p>
<h3>Make sure the Arguments to the UDF refers to ALL the cells the UDF uses.</h3>
<p>Change the UDF to<br />
<code><br />
Function Depends(theCell1 as range, theCell2 as range)<br />
Depends = <code>theCell1.Resize(1, 1)</code>+ _<br />
theCell1.Resize(1, 1).Offset(0, 1) + theCell2<br />
End Function<br />
</code><br />
This is the best solution.</p>
<p>Call it using <strong>=Depends(A1:B1,Z9)</strong> so that Excel knows that B1 is being referenced by theCell1.Offset(0,1).</p>
<p>Now Excel knows all the cells that the function depends on and it will be recalculated correctly and efficiently.</p>
<h3>Detecting whether a Function or Formula is Volatile</h3>
<p>You can download VolatileFuncs.zip from <a href="http://www.DecisionModels.com/Downloads/VolatileFuncs.zip">http://www.DecisionModels.com/Downloads/VolatileFuncs.zip</a></p>
<p>This contains tests for the volatile Excel built-in functions, using a function to increment a counter each time the referenced cell changes.<code><br />
Public jCalcSeq As Long ''' calculation sequence counter<br />
'<br />
Public Function CalcSeqCountRef(theRange As Range) As Variant<br />
'<br />
' COPYRIGHT © DECISION MODELS LIMITED 2000. All rights reserved<br />
'<br />
' increment calculation sequence counter at Full Recalc or when theRange changes<br />
' fixed for false dependency<br />
'<br />
jCalcSeq = jCalcSeq + 1<br />
CalcSeqCountRef = jCalcSeq + (theRange = theRange) + 1<br />
End Function</code></p>
<h2>Summary</h2>
<p><strong>Make sure that the arguments to your UDF always directly refer to ALL the cells that the UDF uses.</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/319/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/319/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/319/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=319&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2012/02/02/writing-efficient-vba-udfs-part-10-volatile-functions-and-function-arguments/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>Writing Efficient UDFs Part 9 &#8211; An Example &#8211; Updated</title>
		<link>http://fastexcel.wordpress.com/2012/01/31/writing-efficient-udfs-part-9-an-example/</link>
		<comments>http://fastexcel.wordpress.com/2012/01/31/writing-efficient-udfs-part-9-an-example/#comments</comments>
		<pubDate>Tue, 31 Jan 2012 17:25:16 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Calculation]]></category>
		<category><![CDATA[UDF]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=312</guid>
		<description><![CDATA[Pedro wants to know how to speed up his UDF, which needs to calculate results for 35040 cells the minimum difference between the cell and a column of values of unknown length. Pedro&#8217;s UDF Function MinofDiff(r1 As Long) As Variant Dim r2 As Range Dim TempDif As Variant Dim TempDif1 As Variant Dim j As [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=312&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Pedro wants to know how to speed up his UDF, which needs to calculate results for 35040 cells the minimum difference between the cell and a column of values of unknown length.</p>
<h3>Pedro&#8217;s UDF</h3>
<p><code>Function MinofDiff(r1 As Long) As Variant<br />
Dim r2 As Range<br />
Dim TempDif As Variant<br />
Dim TempDif1 As Variant<br />
Dim j As Long<br />
Dim LastRow As Long<br />
On Error GoTo FuncFail<br />
If r1 = 0 Then GoTo skip<br />
With Sheets("Dados")<br />
LastRow = .Cells(.Rows.Count, "P").End(xlUp).Row<br />
Set r2 = .Range("P8", "P" &amp; LastRow)<br />
End With<br />
TempDif1 = Application.Max(r2)<br />
For j = 1 To LastRow – 7<br />
If r1 &gt;= r2(j) Then<br />
TempDif = r1 – r2(j)<br />
Else<br />
TempDif = r1<br />
End If<br />
MinofDiff = Application.Min(TempDif, TempDif1)<br />
TempDif1 = MinofDiff<br />
Next j<br />
skip:<br />
Exit Function<br />
FuncFail:<br />
MinofDiff = CVErr(xlErrNA)<br />
End Function<br />
</code><br />
There is a fundamental problem with Pedro&#8217;s UDF: it is referencing a range in column P without passing it in as a parameter, so if anything changes in column P the UDF could give the wrong answer because Excel will not recalculate it. Pedro has done this so that the UDF can dynamically adjust to the number of entries in column P.</p>
<p>On test data with 60000 entries in column P 20 calls to the UDF take 18.5 seconds on my laptop, so 34K calls would take about 9 hours to calculate! So why is it so slow?</p>
<ul>
<li>Every time the function is called (35K times) it finds the last row and the MAX value in column P: but this only needs to be done once.</li>
<li>35040 calls will hit the <a href="http://fastexcel.wordpress.com/2011/06/13/writing-effici…be-refresh-bug/ ‎">VBE refresh slowdown bug</a>: so we need to bypass that.</li>
<li>The For loop is referencing each cell value in column P (using R2(j) ) twice. Each reference to a cell is slow because there is a <a title="VBA Read/write Speed Formula – Benchmarking Excel Versions" href="http://fastexcel.wordpress.com/2011/06/13/vba-readwrite-speed-formula-benchmarking-excel-versions/">large overhead for each call out to the Excel object model.</a></li>
<li>The UDF uses Worksheetfunction.Min to find out which of 2 values is smaller: its much quicker to compare the values using VBA If than invoking a worksheet function.</li>
</ul>
<h3>The revised UDF</h3>
<p>To solve the fundamental problem with the UDF I will pass it an additional parameter: a whole column reference to column P. Then the UDF can resize the range to the last cell containing data. (Another alternative would be to create a Dynamic Named Range for column P and pass that as a parameter.</p>
<p>To solve the first 2 slowdown problems the UDF will be made into an<a href="http://fastexcel.wordpress.com/2011/06/20/writing-efiici…ulas-go-faster/ ‎"> array formula UDF</a> that returns an array of 35040 results.</p>
<p>To avoid referencing each cell in column P twice inside the loop, the UDF will <a title="Writing efficient VBA UDFs (Part 1) – It ain’t what you do it’s the way that you do it" href="http://fastexcel.wordpress.com/2011/05/25/writing-efficient-vba-udfs-part-1/">get all the values from column P once, into a variant array </a>and then loop on the variant array.<br />
<code><br />
Function MinofDiff2(R1 As Range, R2 As Range) As Variant<br />
Dim R2Used As Range<br />
Dim vArr2 As Variant<br />
Dim vArr1 As Variant<br />
Dim vOut() As Double<br />
Dim TempDif As Double<br />
Dim TempDif1 As Double<br />
Dim D1 As Double<br />
Dim D2 As Double<br />
Dim TMax As Double<br />
Dim j1 As Long<br />
Dim j2 As Long<br />
Dim LastRow As Long<br />
'<br />
On Error GoTo FuncFail<br />
'<br />
' handle full column<br />
'<br />
LastRow = R2.Cells(R2.Rows.Count, 1).End(xlUp).Row<br />
Set R2Used = R2.Resize(LastRow - 7, 1).Offset(7, 0)<br />
'<br />
' get values into arrays<br />
'<br />
vArr2 = R2Used.Value2<br />
vArr1 = R1.Value2<br />
'<br />
' find max<br />
'<br />
TMax = Application.Max(R2Used)<br />
'<br />
' set output array to same size as R1<br />
'<br />
ReDim vOut(1 To UBound(vArr1), 1)<br />
'<br />
' loop on R1<br />
'<br />
For j1 = 1 To UBound(vArr1)<br />
TempDif1 = TMax<br />
D1 = vArr1(j1, 1)<br />
'<br />
' loop on R2<br />
'<br />
For j2 = 1 To (LastRow - 7)<br />
D2 = vArr2(j2, 1)<br />
If D1 &gt;= D2 Then<br />
TempDif = D1 - D2<br />
Else<br />
TempDif = D1<br />
End If<br />
If TempDif &lt; TempDif1 Then<br />
vOut(j1, 1) = TempDif<br />
Else<br />
vOut(j1, 1) = TempDif1<br />
End If<br />
TempDif1 = vOut(j1, 1)<br />
Next j2<br />
Next j1<br />
MinofDiff2 = vOut<br />
skip:<br />
Exit Function<br />
FuncFail:<br />
MinofDiff2 = CVErr(xlErrNA)<br />
End Function<br />
</code></p>
<p>Because this is an array function you need to select the 35040 cells that you want to contain the answer, then type the formula into the formula bar =MinofDiff2(A1:A35040,P:P) and then press Ctrl/Shift/Enter to enter the formula as an array formula into the 35040 cells.</p>
<p>This revised UDF takes .222 seconds for 20 values, and completes the 35040 UDF calculations in 6.25 minutes, a speedup factor of over 80.</p>
<h3>Updated with Harlan Grove&#8217;s suggestions</h3>
<p>Harlan Grove has pointed out several ways of speeding up the UDF. Here is a revised version implementing most of his suggestions. It is about 17% faster than my original version.</p>
<p><code><br />
Function MinofDiff3(R1 As Range, R2 As Range) As Variant<br />
Dim R2Used As Range<br />
Dim vArr2 As Variant<br />
Dim vArr1 As Variant<br />
Dim vOut() As Double<br />
Dim TempDif As Double<br />
Dim TempDif1 As Double<br />
Dim D1 As Double<br />
Dim D2 As Double<br />
Dim TMax As Double<br />
Dim TMin As Double<br />
Dim j1 As Long<br />
Dim j2 As Long<br />
Dim LastRow As Long<br />
'<br />
On Error GoTo FuncFail<br />
'<br />
' handle full column<br />
'<br />
LastRow = R2.Cells(R2.Rows.Count, 1).End(xlUp).Row - 7<br />
Set R2Used = R2.Resize(LastRow, 1).Offset(7, 0)<br />
'<br />
' get values into arrays<br />
'<br />
vArr2 = R2Used.Value2<br />
vArr1 = R1.Value2<br />
'<br />
' find max &amp; Min<br />
'<br />
TMax = Application.Max(R2Used)<br />
TMin = Application.Min(R2Used)<br />
'<br />
' set output array to same size as R1<br />
'<br />
ReDim vOut(1 To UBound(vArr1), 1)<br />
'<br />
' loop on R1<br />
'<br />
For j1 = 1 To UBound(vArr1)<br />
TempDif1 = TMax<br />
D1 = vArr1(j1, 1)<br />
TempDif = D1 - TMax<br />
If D1 &gt; TMax Then<br />
If TempDif &lt; TMax Then<br />
vOut(j1, 1) = TempDif<br />
Else<br />
vOut(j1, 1) = TMax<br />
End If<br />
Else<br />
If D1 &lt; TMin Then<br />
vOut(j1, 1) = D1<br />
Else<br />
'<br />
' loop on R2<br />
'<br />
For j2 = 1 To LastRow<br />
D2 = vArr2(j2, 1)<br />
If D1 &gt;= D2 Then<br />
TempDif = D1 - D2<br />
Else<br />
TempDif = D1<br />
End If<br />
If TempDif &lt; TempDif1 Then TempDif1 = TempDif<br />
vOut(j1, 1) = TempDif1<br />
Next j2<br />
End If<br />
End If<br />
Next j1<br />
MinofDiff3 = vOut<br />
skip:<br />
Exit Function<br />
FuncFail:<br />
MinofDiff3 = CVErr(xlErrNA)<br />
End Function<br />
</code></p>
<p>Harlan also points out that a version using QuickSort to sort R2 and Binary Search instead of the loop would be an order of magnitude faster!</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/312/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/312/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/312/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=312&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2012/01/31/writing-efficient-udfs-part-9-an-example/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>Excel 2010 Tables/Listobject: slow update  and how to bypass</title>
		<link>http://fastexcel.wordpress.com/2012/01/30/excel-2010-tableslistobject-slow-update-and-how-to-bypass/</link>
		<comments>http://fastexcel.wordpress.com/2012/01/30/excel-2010-tableslistobject-slow-update-and-how-to-bypass/#comments</comments>
		<pubDate>Mon, 30 Jan 2012 12:50:08 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Calculation]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=303</guid>
		<description><![CDATA[There was an interesting post on Stack Overflow recently about a performance problem when updating Excel 2007/2010 Tables/Listobjects. Certainly something strange is going on! Duplicating the Problem 1. Create a table by selecting a few cells (I used A1:A3) on a sheet (Sheet1) and using Format as Table on the Home tab 2. On a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=303&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There was an interesting <a href="http://stackoverflow.com/questions/8865296/excel-list-object-vba-performance-bug">post on Stack Overflow</a> recently about a performance problem when updating Excel 2007/2010 Tables/Listobjects. Certainly something strange is going on!</p>
<h2>Duplicating the Problem</h2>
<p>1. Create a table by selecting a few cells (I used A1:A3) on a sheet (Sheet1) and using Format as Table on the Home tab</p>
<p>2. On a different sheet (Sheet2) create a few thousand (I used 10000) of the simplest formula you can think of (I used =&#8221;A&#8221;)</p>
<p>3. Create a VBA Sub that updates a different cell in the same sheet as the table:</p>
<p><code><br />
Sub Updater()<br />
Dim j As Long<br />
Dim dTime As Double<br />
Application.ScreenUpdating = False<br />
Application.Calculation = xlCalculationManual<br />
dTime = Timer<br />
For j = 1 To 10000<br />
Worksheets("Sheet1").Range("d5") = j<br />
Next j<br />
MsgBox Timer - dTime<br />
End Sub<br />
</code></p>
<p>4. Select a cell within the Table</p>
<p>5. Run the VBA Sub</p>
<p>On my system that takes 8.8 seconds.</p>
<h2>Bypassing the Problem</h2>
<p>For this slowdown to occur each of the following conditions must be true:</p>
<ul>
<li>A cell within the Table must be selected</li>
<li>The sheet containing the Table must be the Active Sheet</li>
<li>The cell being updated must be on the same sheet as the table, but does not have to be within the table</li>
<li>There must be a reasonable number of formulas in the workbook.</li>
</ul>
<p>So change any or all of these conditions or delete all the formulas and the update will only take 0.5 seconds on my system.</p>
<h2>Whats actually happening?</h2>
<p>The time taken is proportional mostly to the number and slightly to the size of the formulas in the workbook, but none of the formulas are actually being calculated.</p>
<p>So it seems to me that each time the cell is updated Excel is scanning all the formulas in the workbook as though they might need to be changed.</p>
<p>Maybe this has something to do with the automatic extension of formulas within a table when you add a new row or the fact that the Table definition and its associated Name has to change if you add a new row.</p>
<p>But the fact that the slowdown only occurs if the Table is on the active sheet means that I think this is a bug.</p>
<h2>Can you think of a better explanation?</h2>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/303/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/303/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/303/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=303&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2012/01/30/excel-2010-tableslistobject-slow-update-and-how-to-bypass/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>Writing efficient VBA UDFs (Part 8) – Getting the previously calculated value from the calling cells</title>
		<link>http://fastexcel.wordpress.com/2012/01/08/writing-efficient-vba-udfs-part-8-getting-the-previously-calculated-value-from-the-calling-cells/</link>
		<comments>http://fastexcel.wordpress.com/2012/01/08/writing-efficient-vba-udfs-part-8-getting-the-previously-calculated-value-from-the-calling-cells/#comments</comments>
		<pubDate>Sun, 08 Jan 2012 17:46:27 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Calculation]]></category>
		<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[XLL]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=294</guid>
		<description><![CDATA[If you have a UDF that depends on some slow-calculating resource you may want the UDF to mostly just return the values obtained  at the last calculation from the cells the UDF occupies, and only occasionally go and use the slow-calculating resource. In Excel 2010 you can create efficient C++ XLL UDFs that execute asynchronously [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=294&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>If you have a UDF that depends on some slow-calculating resource you may want the UDF to mostly just return the values obtained  at the last calculation from the cells the UDF occupies, and only occasionally go and use the slow-calculating resource.</p>
<p>In Excel 2010 you can create efficient C++ XLL UDFs that execute asynchronously and multithreaded, which can be a very effective solution.</p>
<p>But how do you get the previous value from the cells calling a VBA UDF?</p>
<p>Lets suppose that you want to pass the UDF a parameter for the slow-calculating resource and a switch to tell it when to use the slow resource. You can set the switch (I am using a defined name called &#8220;RefreshSlow&#8221;)  and refresh the UDFs in a VBA sub like this:<code></code></p>
<p>Sub RefreshUDFs()<br />
Dim lCalcMode As Long<br />
lCalcMode = Application.Calculation<br />
Application.Calculation = xlCalculationManual<br />
Names(&#8220;RefreshSlow&#8221;).RefersTo = True<br />
Calculate<br />
Names(&#8220;RefreshSlow&#8221;).RefersTo = False<br />
Application.Calculation = lCalcMode<br />
End Sub</p>
<p>I will use a dummy function to simulate getting a slow resource:<br />
<code><br />
Function GetSlowResource(vParam As Variant) As Variant<br />
Dim j As Long<br />
For j = 1 To 10000000<br />
Next j<br />
GetSlowResource = Rnd()<br />
End Function<br />
</code><br />
This function (ignores the parameter) and just (slowly) returns a random number.</p>
<p>There are several ways of getting the previously calculated value for a UDF: they each have advantages and disadvantages.</p>
<h3>Application.Caller.Value</h3>
<p>You can use Application.Caller.Value, but this causes a circular reference that you have to switch on Iteration to solve. This is slow and can mask other unintentional circular refs, so its not recommended.</p>
<p><code><br />
Function UDF1(vParam, Refresh)<br />
If Not Refresh Then<br />
UDF1 = Val(Application.Caller.Value2)<br />
Else<br />
UDF1 = GetSlowResource(vParam)<br />
End If<br />
End Function<br />
</code></p>
<h3>Application.Caller.Text</h3>
<p>If you use Application.Caller.Text you don&#8217;t get the circular reference, but it retrieves the formatted value that is displayed in the cell as a string. So if the cell is formatted as a number with 2 decimal places the retrieved value will be truncated to 2 decimal places.<br />
<code><br />
Function UDF2(vParam, Refresh)<br />
If Not Refresh Then<br />
UDF2 = Val(Application.Caller.Text)<br />
Else<br />
UDF2 = GetSlowResource(vParam)<br />
End If<br />
End Function<br />
</code><br />
This solution will work OK if you can control the formatting or the function returns a string.</p>
<h3>Application.Caller.ID</h3>
<p>You can use the Range.ID property to store and retrieve a string value within the UDF.<br />
<code><br />
Function UDF3(vParam, Refresh)<br />
Dim var As Variant<br />
If Not Refresh Then<br />
UDF3 = Val(Application.Caller.ID)<br />
Else<br />
var = GetSlowResource(vParam)<br />
UDF3 = var<br />
Application.Caller.ID = var<br />
End If<br />
End Function<br />
</code><br />
This works well, except that the Range.ID property is not stored in a Saved workbook, so the next time you open the workbook the retrieved value will be Blank/Zero.</p>
<h3>Using an XLM or XLL function to pass the Previous value to the UDF</h3>
<p>Using XLM or XLL technology it is possible to create a non-multi-threaded command-equivalent function to retrieve the previous value.<br />
Here is the code for an XLL+ function called PREVIOUS which has a parameter to make it Volatile or not Volatile.<br />
(Command-equivalent functions default to Volatile but when using it to pass the previous value to a VBA UDF you generally want it to be non-volatile).<br />
This function also works for multi-celled array formulae. <strong><br />
Edited following Keith Lewis comment.</strong><br />
<code><br />
CXlOper* PREVIOUS_Impl(CXlOper&amp; xloResult, const CXlOper* Volatile_op)<br />
{<br />
// Input buffers<br />
bool Volatile;<br />
// Validate and translate inputs<br />
static CScalarConvertParams Volatile__params(L"Volatile",<br />
XLA_DEFAULT_ZERO|XLA_DEFAULT_EMPTY|XLA_DEFAULT_NONNUMERIC|<br />
XLA_DEFAULT_BLANK, 0, -1, true);<br />
XlReadScalar(*Volatile_op, Volatile, Volatile__params);<br />
// End of generated code<br />
//}}XLP_SRC<br />
// defined as a macro function defer recalc so that the func gets previous results<br />
CXlOper xloCaller,xlo;<br />
CXlOper arg;<br />
arg=true;<br />
if (!Volatile) arg=false;<br />
// set volatility of this function: 237 is the function number for volatile<br />
xlo.Excel(237,1,&amp;arg);<br />
// Get caller. Fail if it is not a range of cells<br />
if ( ( xloCaller.GetCaller() != 0 ) || !xloCaller.IsRef() ) return CXlOper::RetError(xlerrNA);<br />
//coerce the caller ref<br />
xloResult.Coerce(xloCaller);<br />
return xloResult.Ret();<br />
}<br />
</code></p>
<p>Then you can use this to pass the previous value to the UDF.<br />
<code><br />
Function UDF4(vParam, Refresh, Previous)<br />
Dim var As Variant<br />
If Not Refresh Then<br />
UDF4 = Previous<br />
Else<br />
var = GetSlowResource(vParam)<br />
UDF4 = var<br />
End If<br />
End Function<br />
</code><br />
The UDF is called from a formula like this =UDF4(&#8220;AAPL&#8221;,RefreshSlow,PREVIOUS(False))</p>
<p>This works well, but requires access to the XLL PREVIOUS function (Laurent Longre&#8217;s MOREFUNC addin has a similar function).</p>
<p>Its supposed to be possible to write a similar function using the old XLM Macro language, but I have not tried it.</p>
<h2>Conclusion</h2>
<p>There are several ways of getting the previous value from the last calculation for a VBA UDF. But the best solution requires using a C++ XLL.</p>
<p><strong>Special prize to the first person to write the XLM Macro Previous UDF!</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/294/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/294/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/294/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=294&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2012/01/08/writing-efficient-vba-udfs-part-8-getting-the-previously-calculated-value-from-the-calling-cells/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>UK Excel Developer Conference: London January25</title>
		<link>http://fastexcel.wordpress.com/2011/12/18/uk-excel-developer-conference-london-january25/</link>
		<comments>http://fastexcel.wordpress.com/2011/12/18/uk-excel-developer-conference-london-january25/#comments</comments>
		<pubDate>Sun, 18 Dec 2011 17:49:52 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>
		<category><![CDATA[XLL]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=289</guid>
		<description><![CDATA[Simon Murphy (AKA Smurf) has organised another one-day conference for UK Developers in London on January 25. The last one was a great chance to learn some awesome stuff, meet some fellow Excel developer geeks and consume some beer, and this one promises to be even better The agenda is here (subject to change of [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=289&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Simon Murphy (<a href="http://smurfonspreadsheets.wordpress.com/">AKA Smurf</a>) has organised another one-day conference for UK Developers in London on January 25.</p>
<p>The last one was a great chance to learn some awesome stuff, meet some fellow Excel developer geeks and consume some beer, and this one promises to be even better</p>
<p>The agenda is <a href="http://xlconf.wordpress.com/2011/11/22/uk-excel-developer-conference-london-january-2012/">here</a> (subject to change of course), and you can sign up <a href="http://www.codematic.net/donations.htm">here</a>. (its an absolute bargain at £200).</p>
<p>My session is called VBA to C : Pratfalls and Perils</p>
<table border="0" rules="none" cellspacing="0">
<tbody>
<tr>
<td align="left" valign="top" height="101">15:30 – 16:30</td>
<td align="left" valign="top"></td>
<td align="left" valign="top">VBA to C : Pratfalls and Perils<br />
- Stories based on a c++ newby’s efforts to convert 10K lines of VBA UDFs to<br />
C++ XLLs.<br />
- Demonstrations and examples using Visual Studio 2010 and Planatech XLL+</td>
</tr>
</tbody>
</table>
<p>If you want to know why I embarked on this somewhat perilous journey see my post on <a title="Excel UDF Technology Choices – Snakes &amp; ladders with VBA, VB6, .NET, C++, COM, XLL, Interop …" href="http://fastexcel.wordpress.com/2011/07/07/excel-udf-technology-choices-snakes-ladders-with-vba-vb6-net-c-com-xll-interop/">UDF Technology choices</a>.</p>
<p>The idea of this session is very much to approach C++ XLLs from the viewpoint of a VBA developer.</p>
<p>I aim to start with some simple UDFs, then cover some of the more idiotic mistakes that I keep making,<br />
and progress to slightly more sophisticated stuff that demonstrates how to use some of the XLL+ wizard features.</p>
<p>If there is time I will show how relatively easy it turned out to be (once I figured out HOW) to do multi-threaded UDFs with shared memory &#8230;</p>
<p><strong>So <a href="http://www.codematic.net/donations.htm">sign up</a> and come along for a great time and some really interesting and important stuff!</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/289/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/289/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/289/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=289&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/12/18/uk-excel-developer-conference-london-january25/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>TEXT vs VALUE vs VALUE2 &#8211; Slow TEXT and how to avoid it</title>
		<link>http://fastexcel.wordpress.com/2011/11/30/text-vs-value-vs-value2-slow-text-and-how-to-avoid-it/</link>
		<comments>http://fastexcel.wordpress.com/2011/11/30/text-vs-value-vs-value2-slow-text-and-how-to-avoid-it/#comments</comments>
		<pubDate>Wed, 30 Nov 2011 19:40:16 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=271</guid>
		<description><![CDATA[I was intrigued by a recent post pointing out that using .Text to retrieve data from Excel ranges got slower and slower as you iterated through the rows. So I took some time to explore and compare the three main properties (Range.Value, Range.Value2 and Range.Text)  for getting result values from an Excel Range into VBA. [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=271&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I was intrigued by a recent <a href="http://answers.microsoft.com/en-us/office/forum/office_2007-customize/the-text-property-causes-code-to-execute-slower/81896ab0-ef96-4bb0-a60b-6f6a2bf9a5a1">post</a> pointing out that using .Text to retrieve data from Excel ranges got slower and slower as you iterated through the rows. So I took some time to explore and compare the three main properties (Range.Value, Range.Value2 and Range.Text)  for getting result values from an Excel Range into VBA.</p>
<p>Of course, as you will see, they each have their own peculiarities and advantages.</p>
<h3>Range.Text</h3>
<p>This gets the <strong>formatted</strong> value of a cell. Actually it looks like .Text gets the value from the cell and then formats it, because the more complex the formatting the slower it is.<br />
.Text is a read-only property, so you cannot set it directly.</p>
<p>If you try getting .Text from multiple cells into a variant (varr = Range(&#8220;A1:A10&#8243;).Text) you do NOT get an array of results. Instead if all the cells in the range contain the same value formatted in the same way you get a single formatted value, but <strong>if ANY of the cells has different values or formats you get Null</strong> (<strong><em> this could be a useful trick</em></strong>).</p>
<p>When used inside a UDF you can use .Text to get the formatted value of the calling cell as it was before the UDF was called (you can&#8217;t do this with .Value or .Value 2 without causing a circular reference). Here is an example that adds an extra . on each calculation.<br />
<code><br />
Function LastValue()<br />
Dim var As Variant<br />
Application.Volatile<br />
var = Application.Caller.Text<br />
Debug.Print var<br />
var = var &amp; "."<br />
LastValue = var<br />
End Function<br />
</code><br />
The major drawback of .Text when used this way is that it gives you the formatted value, so the value you get could be ### if the user has set an inappropriate zoom or column width, or numbers could be retrieved as 1E+18 or &#8230;</p>
<h3>Range.Value</h3>
<p>This <strong>mostly</strong> gets the underlying value from the cell.</p>
<p>But if the cell is formatted as a date or currency then Range.Value converts the underlying value into a VBA date or currency variable before passing it to the VBA variable used in the assignment statement. Since VBA currency only has 4 decimal places this can cause a loss of accuracy. Suppose cell G4 has a value of 123.456789 formatted as currency. Then Range(&#8220;g4&#8243;).Value will retrieve a value of 123.4568 rather than the actual value!<br />
If you assign this to a Variant you get a variant with a subtype of currency, but if you assign it to a Double then the value first gets converted to currency datatype and truncated, and then the currency datatype gets converted to a double.</p>
<p>Maybe using .Value to retrieve cells formatted as dates into a variant is useful because then you can use IsDate() to detect that the cell was a date.</p>
<p>Range.Value is an efficient way of transferring a range of cell values to VBA because you can assign the Range to a variant variable and the you get a variant containing a 2-dimensional array of variants. This is much more efficient that looping on the cells one-by-one.</p>
<p>.Value is (unfortunately) the default property of the Range object.</p>
<h3>Range.Value2</h3>
<p>This works the same way as Range.Value, except that it <strong>does not check the cell format and convert to Date or Currency</strong>. And thats probably why <strong>its faster than .Value</strong> when retrieveing numbers.</p>
<p>So .Value2 really should be the default, and is definitely the one to use 99% of the time.</p>
<h3>Performance Comparison</h3>
<p>So how do these properties compare for speed? Here is my test code:<br />
<code><br />
Sub textit()<br />
Dim dTime As Double<br />
Dim j As Long<br />
Dim jStart As Long<br />
Dim var As Variant<br />
dTime = MicroTimer()<br />
For jStart = 1 To 40000 Step 5000<br />
dTime = MicroTimer<br />
For j = 1 To 5000<br />
var = Range("a1").Offset(jStart + j - 2, 0).Text<br />
Next j<br />
dTime = MicroTimer - dTime<br />
Debug.Print dTime<br />
Next jStart<br />
End Sub<br />
</code><br />
I ran this using a fresh worksheet with test data of numbers in the first 40000 rows.</p>
<p>The first run showed more-or-less constant time for each block. Then I changed the row-height of 10 rows at random intervals. The next run (.Text(2) is much slower, and the times increase from block to block.</p>
<p><a href="http://fastexcel.files.wordpress.com/2011/11/text12.png"><img class="wp-image-277 aligncenter" title="Text12" src="http://fastexcel.files.wordpress.com/2011/11/text12.png?w=153&#038;h=203" alt="" width="153" height="203" /></a></p>
<p>So what&#8217;s going on: why so much slower with times increasing?</p>
<p>Well it turns out that once enough row-heights have been changed the time for .Text is a function of the number of rows between the selected visible rows on the screen and the row being processed!!!!</p>
<p><em><strong>(And No I don&#8217;t know why, .Text must be doing some sort of cumulative row height calculation).</strong></em></p>
<p>So if you add <strong>Range(&#8220;a1&#8243;).Offset(jStart).Select</strong> immediately after the <strong>For jStart = 1 To 40000 Step 5000</strong> you get a faster and more constant set of times. Note you have to have Application.Screenupdating =True or this trick won&#8217;t work.</p>
<p><a href="http://fastexcel.files.wordpress.com/2011/11/text123.png"><img class="size-full wp-image-278 aligncenter" title="Text123" src="http://fastexcel.files.wordpress.com/2011/11/text123.png?w=450" alt=""   /></a></p>
<p>Finally I replaced .Text with .Value and then with .Value2, and then used a variant array instead of the inner loop to get the full set of timings:</p>
<h2><a href="http://fastexcel.files.wordpress.com/2011/11/text1234.png"><img class="size-full wp-image-280 aligncenter" title="text1234" src="http://fastexcel.files.wordpress.com/2011/11/text1234.png?w=450&#038;h=181" alt="" width="450" height="181" /></a></h2>
<h2></h2>
<h2>Conclusions</h2>
<ul>
<li>.Text is seriously slow even if you bypass the row-height problem.</li>
<li>.Value can seriously damage your<del></del> numbers</li>
<li>.Value2 is faster than .value with numbers (no significant difference with text)</li>
<li>.Value2 using a variant array is much the fastest way to go</li>
</ul>
<h3>So do you ever use .Text? And if so why?</h3>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/271/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/271/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/271/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=271&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/11/30/text-vs-value-vs-value2-slow-text-and-how-to-avoid-it/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/11/text12.png" medium="image">
			<media:title type="html">Text12</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/11/text123.png" medium="image">
			<media:title type="html">Text123</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/11/text1234.png" medium="image">
			<media:title type="html">text1234</media:title>
		</media:content>
	</item>
		<item>
		<title>Writing efficient VBA UDFs (Part 7) – UDFs calculated multiple times</title>
		<link>http://fastexcel.wordpress.com/2011/11/25/writing-efficient-vba-udfs-part-7-udfs-calculated-multiple-times/</link>
		<comments>http://fastexcel.wordpress.com/2011/11/25/writing-efficient-vba-udfs-part-7-udfs-calculated-multiple-times/#comments</comments>
		<pubDate>Fri, 25 Nov 2011 16:09:11 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=261</guid>
		<description><![CDATA[There are several circumstances where Excel will calculate a UDF multiple times when you would expect it to only be calculated once. This can be a significant problem if your UDF takes a long time to execute. The previous posts on writing efficient VBA UDfs (Part1,Part2,Part3,Part4,Part5 Part6 ) have not discussed this problem so I [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=261&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>There are several circumstances where Excel will calculate a UDF multiple times when you would expect it to only be calculated once. This can be a significant problem if your UDF takes a long time to execute.<br />
The previous posts on writing efficient VBA UDfs (<a title="Writing efficient VBA UDFs (Part 1) – It ain’t what you do it’s the way that you do it" href="../2011/10/18/2011/05/25/writing-efficient-vba-udfs-part-1/">Part1</a>,<a title="Writing efficient VBA UDFs (Part 2) – using Excel Functions inside a UDF" href="../2011/10/18/2011/06/06/writing-efficient-vba-udfs-part-2/">Part2</a>,<a title="Writing efficient VBA UDFs (Part 3) – Avoiding the VBE refresh bug" href="../2011/10/18/2011/06/13/writing-efficient-vba-udfs-part-3-avoiding-the-vbe-refresh-bug/">Part3</a>,<a title="Writing efficient VBA UDFs (Part 4) – Variants, References, Arrays, Calculated Expressions, Scalars" href="../2011/06/20/writing-efficient-vba-udfs-part-4-variants-references-arrays-calculated-expressions-scalars/">Part4</a>,<a title="Writing efficient VBA UDFs (Part5) – UDF Array Formulas go faster!" href="../2011/06/20/writing-efiicient-vba-udfs-part5-udf-array-formulas-go-faster/">Part5 </a><a title="Writing efficient VBA UDFs (Part 6) – Faster string handling and Byte arrays" href="http://fastexcel.wordpress.com/2011/10/18/writing-efficient-vba-udfs-part-6-faster-strings-and-byte-arrays/">Part6 </a>) have not discussed this problem so I will show how to get around it.</p>
<h2>Multiple UDF recalcs caused by uncalculated cells</h2>
<p>When Excel recalcs a workbook after changes have been made the calculation engine starts by calculating the most recently changed formulas, and then uses the most recent calculation sequence for the remaining formulas.<br />
If the calculation engine finds a formula that depends on a cell that has been dirtied/changed (or is volatile) but has not yet been calculated, <em>it reschedules the formula to the end of the calculation chain so that it can be recalculated again after the uncalculated cell.</em><br />
The problem is that the calculation engine only does this rescheduling <strong>after the formula/UDF has been calculated</strong>, so a formula containing a UDF can be calculated many times in each recalculation.</p>
<p>Here is a very simple example:</p>
<ol>
<li>Set Calculation to Manual so that its easier to see whats happening.</li>
<li>Enter this UDF into a standard Module in the VBE.<code>Public Function Tracer(theCell As Range)<br />
Tracer = theCell.Value<br />
Debug.Print Application.Caller.Address &amp; "-" &amp; Tracer<br />
End Function</code></li>
<li>Show the Immediate Window (Ctrl G)</li>
<li>Enter 1 in Cell A1</li>
<li>Enter =Tracer(A1)+1 in cell A2</li>
<li>Enter =Tracer(A2)+1 in cell A3</li>
</ol>
<p>The Immediate window shows<br />
$A$2-1<br />
$A$3-2<br />
because the formulas were calculated as they were entered.<br />
Now clear the immediate window, return to Excel and press F9 to recalculate. The immediate Window now shows<br />
$A$3-<br />
$A$2-1<br />
$A$3-2<br />
Which shows that cell A3 was calculated first (with the value of its parameter range A2 showing as empty), followed by A2, followed by A3 again, this time with the correct value for its parameter A2.<br />
Now if you clear the Immediate window and calculate the formulas again without changing anything (use Ctrl/Alt/F9). This time A3 only gets recalculated once, because Excel is reusing the final calculation sequence from the previous recalculation.</p>
<h2>Handling uncalculated cells</h2>
<p>Fortunately its fairly easy for the UDF to detect when its being passed an uncalculated cell because the cell will be empty:<br />
<code><br />
Public Function Tracer2(theCell As Range)<br />
If IsEmpty(theCell) Then Exit Function<br />
Tracer2 = theCell.Value<br />
Debug.Print Application.Caller.Address &amp; "-" &amp; Tracer2<br />
End Function<br />
</code><br />
This version of the UDF checks if the cell is empty and exits immediately. If you need to distinguish between genuinely empty cells and uncalculated cells you can check that the cell contains a formula useing:<br />
<code><br />
=IsEmpty(theCell.Value) and Len(theCell.formula)&gt;0 Then Exit Function</code><br />
or<br />
<code><br />
=IsEmpty(theCell.Value) and theCell.HasFormula Then Exit Function</code></p>
<p>If the parameter is a range of cells containing formulae then you need something a bit more complex:<br />
<code><br />
Public Function IsCalced(theParameter As Variant) As Boolean<br />
'<br />
' Charles Williams 9/Jan/2009<br />
'<br />
' Return False if the parameter refers to as-yet uncalculated cells<br />
'<br />
Dim vHasFormula As Variant<br />
IsCalced = True<br />
On Error GoTo Fail<br />
If TypeOf theParameter Is Excel.Range Then<br />
vHasFormula = theParameter.HasFormula<br />
'<br />
' HasFormula can be True, False or Null:<br />
' Null if the range contains a mix of Formulas and data<br />
'<br />
If IsNull(vHasFormula) Then vHasFormula = True<br />
If vHasFormula Then<br />
'<br />
' CountA returns 0 if any of the cells are not yet calculated<br />
'<br />
If Application.WorksheetFunction.CountA(theParameter) = 0 Then IsCalced = False<br />
End If<br />
ElseIf VarType(theParameter) = vbEmpty Then<br />
'<br />
' a calculated parameter is Empty if it references uncalculated cells<br />
'<br />
IsCalced = False<br />
End If<br />
Exit Function<br />
Fail:<br />
IsCalced = False<br />
End Function<br />
</code></p>
<p>This function handles both range references and calculated ranges (array formula expressions etc) and checks if ALL the cells in the parameter contain formulas and ANY of the cells are uncalculated.</p>
<h2>Only Variant and Range Parameters can be uncalculated.</h2>
<p>Only a UDF parameter defined as a Range or a Variant can be uncalculated. If all your paramters are defined as, for instance, Double then Excel will attempt to coerce the parameter to Double before passing it to the UDF, and if the Paramter actually refers to an uncalculated cell then the UDF will not be called.</p>
<h2>Multiple UDF Recalcs caused by the Function Wizard</h2>
<p>Whenever you use the Function Wizard with a UDF the UDF gets called lots of times, because the Function Wizard uses Evaluate to dynamically show you the result of the function as you enter the parameters for the function. This is not good if your UDF is slow to execute!<br />
You can detect that the UDF has been called by the function wizard by checking if the Standard commandbar is enabled (this works in Excel 2007 and Excel 2010 even though the commandbars are not visible).<br />
<code><br />
If Not Application.CommandBars("Standard").Controls(1).Enabled Then Exit Function<br />
</code></p>
<h2>Multiple UDF Recalcs with multi-cell Array Formula UDFs</h2>
<p>Useing an array UDF that returns results to multiple cells can be a very good way of speeding up UDF execution (see <a title="Writing efficient VBA UDFs (Part5) – UDF Array Formulas go faster!" href="http://fastexcel.wordpress.com/2011/06/20/writing-efiicient-vba-udfs-part5-udf-array-formulas-go-faster/">Part 5 &#8211; Array UDFs go faster</a>), but there is a nasty slowdown bug you should be aware of:<br />
When a multi-cell UDF is entered or modified <em>and depends on a volatile formula</em>: <strong>the UDF is evaluated once for each cell it occupies. </strong>This does not happen when the UDF is recalculated, only when it is entered or changed.</p>
<h2>UDFs in Conditional Formatting formulas.</h2>
<p>Formulas in Conditional Formatting rules get evaluated each time the portion of the screen containing the conditional format gets redrawn or recalculated (you can demonstrate this by using a Debug.Print statement in a UDF being used in a conditional formatting rule). So on the whole using UDFs in Conditional formats is probably not a great idea.</p>
<h1>Conclusion</h1>
<p>If you have UDFs which take a long time to execute it makes sense to add code to check for both uncalculated cells and the UDF being called by the function wizard.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/261/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/261/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/261/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=261&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/11/25/writing-efficient-vba-udfs-part-7-udfs-calculated-multiple-times/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>Evaluate Functions and Formulas fun: How to make Excel&#8217;s Evaluate method twice as fast</title>
		<link>http://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/</link>
		<comments>http://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/#comments</comments>
		<pubDate>Wed, 02 Nov 2011 16:32:46 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[Calculation]]></category>
		<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=246</guid>
		<description><![CDATA[Prompted by a comment from Sam on Match vs Find I thought I would take a look at Excel&#8217;s rather quirky Evaluate method with Excel 2010 to see how it performed. The Evaluate method internally uses Excel&#8217;s formula parser and calculator, and this makes it surprisingly powerful. You can use it on virtually any kind [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=246&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Prompted by a comment from Sam on <a title="MATCH vs FIND vs Variant Array VBA Performance Shootout in Excel 2010" href="http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/">Match vs Find</a> I thought I would take a look at Excel&#8217;s rather quirky Evaluate method with Excel 2010 to see how it performed.</p>
<p>The Evaluate method internally uses Excel&#8217;s formula parser and calculator, and this makes it surprisingly powerful. You can use it on virtually any kind of formula, range reference or Defined Name. But, as we will see, it does have a number of strange &#8220;quirks&#8221; that you have to navigate around.</p>
<p>Depending on the context Evaluate will either return an object (for example a Range) or values.</p>
<p>I will be using exactly the same test setup of 100000 rows of randomly generated XY pairs and timing routine as in <a title="MATCH vs FIND vs Variant Array VBA Performance Shootout in Excel 2010" href="http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/">Match vs Find</a>, so you can directly compare the results.</p>
<h2>Using the square brackets [ ] shortcut for Evaluate</h2>
<p>Sam&#8217;s comment suggested using [COUNTIFS] to see how the timing compared with MATCH and FIND. Of course its not quite the same thing because the loop on Match and Find allows the VBA to do something for each XY pair found. Sam&#8217;s VBA looks like this:</p>
<p><code>Sub FindXY_COUNTIFS1()<br />
Dim j As Long<br />
Dim dTime As Double<br />
dTime = Microtimer<br />
j = [COUNTIFS(A1:A100000,"x",B1:B100000,"y")]<br />
Debug.Print "COUNTIFS1 " &amp; j &amp; " " &amp; (Microtimer - dTime) * 1000<br />
End Sub</code></p>
<p>It takes 11.6 millisecs to find the 25135 XY pairs generated using a constant of 0.5 in the test data generator.</p>
<p>[ ] is a shortcut for Application.Evaluate. The advantage of using the [ ] brackets is that it is concise and the formula inside the [ ] is exactly the same as when used in a worksheet cell. The disadvantage is that you cannot generate the formula as a string. I tend to only use this notation when evaluating my hidden workbook-scoped defined names, because they are not likely to change. (Of course sometimes I get lazy &#8230;)</p>
<h2>Using Application.Evaluate instead of [ ]</h2>
<p>You can use Evaluate or Application.Evaluate with a string instead of the [ ]</p>
<p><code>j = Evaluate("COUNTIFS(A1:A100000," &amp; Chr(34) &amp; "x" &amp; Chr(34) &amp; ",B1:B100000," &amp; Chr(34) &amp; "y" &amp; Chr(34) &amp; ")")</code><br />
<code></code>The timing is virtually identical to the [ ] shortcut method.</p>
<h2>Application.Evaluate and the Activesheet</h2>
<p>One trap for the unwary with [ ] , Evaluate and Application.Evaluate is that all references that do not contain a worksheet (unqualified references like A1:A100000) are assumed to refer to whatever the Active sheet currently happens to be.<br />
So if you are going to use Application.Evaluate you should always use a qualified reference (Sheet1!A1:A100000) unless you like your code to live dangerously.</p>
<h2>Worksheet.Evaluate</h2>
<p>Worksheets and Charts also have an Evaluate Method. When you use these methods unqualified references are assumed to refer to the worksheet or chart.</p>
<p><code>Sub FindXY_COUNTIFS3()<br />
Dim j As Long<br />
Dim dTime As Double<br />
dTime = Microtimer<br />
j = Worksheets("Sheet1").Evaluate("COUNTIFS(A1:A100000," &amp; Chr(34) &amp; "x" &amp; Chr(34) &amp; ",B1:B100000," &amp; Chr(34) &amp; "y" &amp; Chr(34) &amp; ")")<br />
Debug.Print "COUNTIFS3 " &amp; j &amp; " " &amp; (Microtimer - dTime) * 1000<br />
End Sub</code></p>
<p>Now for the surprise: <strong>Worksheet.Evaluate is twice as fast as Application.Evaluate!<br />
</strong>(actually 6.1 millisecs as opposed to 11.6 millisecs)</p>
<p>I am fairly sure that there is a bug in Application.Evaluate that <em>actually does the evaluation twice</em>.<br />
Certainly if you use Application.evaluate on a UDF the UDF will be executed twice.</p>
<h2>Chart.Evaluate</h2>
<p>In the real world I have never actually used Chart.Evaluate (probably because I hate programming Chart objects), but according to Help it seems you can do interesting things with it:</p>
<p>&#8220;Chart Objects. You can specify any chart object name, such as &#8220;Legend&#8221;, &#8220;Plot Area&#8221;, or &#8220;Series 1&#8243;, to access the properties and methods of that object. For example, <code>Charts("Chart1").Evaluate("Legend").Font.Name</code> returns the name of the font used in the legend.&#8221;</p>
<h2>Evaluating Array Formulas</h2>
<p>Amazingly if you give Evaluate an array formula it evaluates it as an array formula:</p>
<p><code>Sub FindXY_COUNTIFS4()<br />
Dim j As Long<br />
Dim dTime As Double<br />
dTime = Microtimer<br />
j = ActiveSheet.Evaluate("SUM((A1:A100000=" &amp; Chr(34) &amp; "x" &amp; Chr(34) &amp; ")*(B1:B100000=" &amp; Chr(34) &amp; "y" &amp; Chr(34) &amp; "))")<br />
Debug.Print "COUNTIFS4 " &amp; j &amp; " " &amp; (Microtimer - dTime) * 1000<br />
End Sub</code></p>
<p>This is quite a lot slower than COUNTIFS: it takes nearly 19 milliseconds.<br />
If you are a SUMPRODUCT fan you could use</p>
<p><code>j = ActiveSheet.Evaluate("SUMPRODUCT(--(A1:A100000=" &amp; Chr(34) &amp; "x" &amp; Chr(34) &amp; "),--(B1:B100000=" &amp; Chr(34) &amp; "y" &amp; Chr(34) &amp; "))")</code><br />
But its not significantly faster.</p>
<h2>Evaluate speed compared to a formula in a cell</h2>
<p>You would expect Evaluate to be slower than Excel natively calculating the formula in a cell. And indeed it is, but its quite close for a single formula;</p>
<p>Countifs Formula 6.0<br />
Evaluate Countifs 6.1</p>
<p>Array Sum Formula 16.9<br />
Evaluate Array Sum 18.9</p>
<h2>Evaluate speed compared to using Application.Worksheetfunction</h2>
<p>It looks like there is a higher overhead to using Evaluate, which is what you would expect.<br />
Here is a version of the FindXY sub using Evaluate with MATCH instead of Worksheetfunction.Match.</p>
<p><code>Sub FindXYEval()<br />
Dim oRng As Range<br />
Dim oLastRng As Range<br />
Dim j As Long<br />
Dim jRow As Long<br />
Dim n As Long<br />
Dim Rw As Long<br />
Dim dTime As Double<br />
dTime = Microtimer<br />
Set oRng = Range("a1:A100000")<br />
Set oLastRng = oRng(oRng.Rows.Count)<br />
Rw = oLastRng.Row<br />
On Error GoTo finish<br />
With Application.WorksheetFunction<br />
Do<br />
Set oRng = Range(oRng(j + 1), oLastRng) '&lt;&lt;&lt; Rw<br />
End With<br />
finish:<br />
Debug.Print "MatchEval " &amp; n &amp; " " &amp; (Microtimer - dTime) * 1000<br />
End Sub</code></p>
<p>This takes 3720 milliseconds compared to 478 milliseconds using Worksheetfunction.Match. There are just over 50000 calls to Evaluate or Match so I reckon the additional overhead of using Evaluate is about 65 Microseconds per call.</p>
<h2>More Evaluate Limitations: Updated</h2>
<ul>
<li>The string being evaluated must be less than 256 characters, even in Excel 2010.</li>
<li>A1 style references can be evaluated in both A1 and R1C1 reference mode (Application.ReferenceStyle), but R1C1 style references can only be evaluated in R1C1 mode.</li>
<li>Relative references in the string are treated as absolute, unless they are contained in defined names in which case the defined name is evaluated with respect to cell A1.</li>
<li>Dates should be in USA format (Month-Day-Year).</li>
<li>Evaluate will return an error value if the string formulae contains external references to closed workbooks or XLM functions.</li>
<li>Using Evaluate INDEX(rng,rownum,COLUMN()) gives incorrect answers except for the first column. Evaluate 0+INDEX(rng,rownum,COLUMN()) works</li>
<li>If the string formula contains a reference to both a UDF and a name it will fail with an error 2029 if the name reference occurs AFTER the UDF reference:</li>
</ul>
<ul>
<ul>
<li>If fred is a named range and xyz() is a user defined VBA function then this statement returns error 2029: application.Evaluate(&#8220;=xyz(b1)+fred&#8221;)</li>
<li>This statement returns the correct value: application.Evaluate(&#8220;=fred+xyz(b1)&#8221;)</li>
<li>Microsoft KB article <a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;823604">823604</a> identifies this problem but does not correctly diagnose the circumstances that cause it.</li>
</ul>
</ul>
<p>You can bypass many of these limitations (at the cost of performance) by inserting the formula string into a worksheet cell and then reading the resulting cell value back into a VBA variable.</p>
<h2>Error Handling</h2>
<p>If Evalaute cannot evaluate the formula string it returns an error rather than raising an error, so the result of Evaluate should always be assigned to a Variant.</p>
<h2>Conclusion</h2>
<ul>
<li>The Evaluate method adds a lot of power to VBA</li>
<li>Always use Worksheet.Evaluate rather than Application.Evaluate: its twice as fast and less error-prone</li>
<li>Using Worksheet.Evaluate has comparable speed to a cell formula but a higher overhead</li>
<li>Worksheetfunction has a lower overhead than Evaluate</li>
<li>Beware the Quirks of Evaluate!</li>
</ul>
<p><strong>So whats your experience of Evaluate?</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/246/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/246/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/246/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=246&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>
	</item>
		<item>
		<title>MATCH vs FIND vs Variant Array VBA Performance Shootout in Excel 2010</title>
		<link>http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/</link>
		<comments>http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/#comments</comments>
		<pubDate>Wed, 26 Oct 2011 18:06:23 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=233</guid>
		<description><![CDATA[When searching unsorted data in VBA I have always tended to use MATCH rather than FIND, mainly because early versions of Excel before Excel 2003 did not allow you to use FIND in UDFs. But prompted by a discussion in one of the Excel forums I thought it was about time I revisited Find and [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=233&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>When searching unsorted data in VBA I have always tended to use MATCH rather than FIND, mainly because early versions of Excel before Excel 2003 did not allow you to use FIND in UDFs.</p>
<p>But prompted by a discussion in one of the Excel forums I thought it was about time I revisited Find and Match to see which performs better in <strong>Excel 2010</strong>, and for good measure lets compare them to getting the data into a variant array and looping through the array.</p>
<h2>Generating Test Data</h2>
<p>Andreas Killer came up with a nice routine for generating test data:</p>
<p><code>Sub Init()<br />
Dim Data(1 To 100000, 1 To 2)<br />
Dim i As Long<br />
Rnd -5<br />
For i = 1 To UBound(Data)<br />
If Rnd &gt; 0.5 Then Data(i, 1) = "X"<br />
If Rnd &gt; 0.5 Then Data(i, 2) = "Y"<br />
Next<br />
Cells.ClearContents<br />
Range("A1").Resize(UBound(Data), UBound(Data, 2)) = Data<br />
End Sub</code></p>
<p>This code randomly generates X in column 1 and Y in column 2 in a range of 100 thousand rows, with the number of Xs and Ys controlled by the constant 0.5<br />
Changing the 0.5 to 0.9 will give few Xs and Ys, and changing it to 0.001 will give lots.</p>
<p>Since the X and the Y are using different random numbers there will be rows with X but no Y and Y but no X, as well as rows with both X and Y.</p>
<p>This makes it easy to test how the various methods compare with different densities of data.</p>
<h2>Timing</h2>
<p>I am using the MicroTimer high-resolution timer API to give timing accuracy at the microsecond (millionths of a second) level, but the timing results will all be in milliseconds.</p>
<p><code>#If VBA7 Then<br />
Private Declare PtrSafe Function getFrequency Lib "kernel32" Alias _<br />
"QueryPerformanceFrequency" (cyFrequency As Currency) As Long<br />
Private Declare PtrSafe Function getTickCount Lib "kernel32" Alias _<br />
"QueryPerformanceCounter" (cyTickCount As Currency) As Long<br />
#Else<br />
Private Declare Function getFrequency Lib "kernel32" Alias _<br />
"QueryPerformanceFrequency" (cyFrequency As Currency) As Long<br />
Private Declare Function getTickCount Lib "kernel32" Alias _<br />
"QueryPerformanceCounter" (cyTickCount As Currency) As Long<br />
#End If<br />
Public Function MicroTimer() As Double<br />
'<br />
' returns seconds<br />
' uses Windows API calls to the high resolution timer<br />
'<br />
Dim cyTicks1 As Currency<br />
Dim cyTicks2 As Currency<br />
Static cyFrequency As Currency<br />
'<br />
MicroTimer = 0<br />
'<br />
' get frequency<br />
'<br />
If cyFrequency = 0 Then getFrequency cyFrequency<br />
'<br />
' get ticks<br />
'<br />
getTickCount cyTicks1<br />
getTickCount cyTicks2<br />
If cyTicks2 &lt; cyTicks1 Then cyTicks2 = cyTicks1<br />
'<br />
' calc seconds<br />
'<br />
If cyFrequency Then MicroTimer = cyTicks2 / cyFrequency<br />
End Function</code></p>
<p>The code uses conditional compilation for the Windows API calls so that it will work for both Excel 2010 32-bit and 64-bit Excel.</p>
<h2>Using FIND</h2>
<p>Here is the test code using Range.Find</p>
<p><code>Sub FindXY1()<br />
Dim oRng As Range<br />
Dim n As Long<br />
Dim dTime As Double<br />
Dim FirstAddress As String<br />
dTime = MicroTimer<br />
'<br />
With Range("a1:A100000")<br />
Set oRng = .Find("X", , xlValues, , , xlNext, False)<br />
If Not oRng Is Nothing Then<br />
FirstAddress = oRng.Address<br />
If oRng.Offset(0, 1) = "Y" Then n = n + 1<br />
Do<br />
Set oRng = .FindNext(oRng)<br />
If Not oRng Is Nothing Then<br />
If oRng.Offset(0, 1) = "Y" And oRng.Address &lt;&gt; FirstAddress Then<br />
n = n + 1<br />
End If<br />
End If<br />
Loop While Not oRng Is Nothing And oRng.Address &lt;&gt; FirstAddress<br />
End If<br />
End With<br />
'<br />
Debug.Print "Find " &amp; n &amp; " " &amp; (MicroTimer - dTime) * 1000<br />
End Sub</code></p>
<p>The Sub does a Range.Find on the 100 thousand rows looking for X, and then checks if column 2 for that cell also contains Y.<br />
Then this is repeated using FindNext until we have looped back to the first range address.<br />
When completed the number of rows with both X and Y (this is less than the number of times an X was found) and the time in milliseconds is shown in the Immmediate window.</p>
<h2>Using Match</h2>
<p>Here is the code using WorksheetFunction.MATCH</p>
<p><code>Sub FindXY2()<br />
Dim oRng As Range<br />
Dim j As Long<br />
Dim n As Long<br />
Dim dTime As Double<br />
dTime = MicroTimer<br />
Set oRng = Range("a1:A100000")<br />
On Error GoTo Finish<br />
With Application.WorksheetFunction<br />
Do<br />
j = .Match("X", oRng, 0)<br />
If oRng(j, 2).Value2 = "Y" Then n = n + 1<br />
Set oRng = oRng.Resize(oRng.Rows.Count - j, 1).Offset(j, 0)<br />
Loop<br />
End With<br />
Finish:<br />
Debug.Print "Match " &amp; n &amp; " " &amp; (MicroTimer - dTime) * 1000<br />
End Sub</code></p>
<p>This Sub works by using Worksheetfunction.Match to find the first occurrence of X within the Range object oRng.<br />
After each X is found oRng is resized to exclude the range already searched.</p>
<p>The loop terminates either when nothing is found (Worksheetfunction.Match raises an error)  or the Resize fails, also raising an error.</p>
<h2>Using a Variant Array</h2>
<p><code>Sub FindXY3()<br />
Dim vArr As Variant<br />
Dim j As Long<br />
Dim n As Long<br />
Dim dTime As Double<br />
dTime = MicroTimer<br />
vArr = Range("a1:B100000").Value2<br />
For j = LBound(vArr) To UBound(vArr)<br />
If vArr(j, 1) = "X" Then<br />
If vArr(j, 2) = "Y" Then<br />
n = n + 1<br />
End If<br />
End If<br />
Next j<br />
Debug.Print "Var array " &amp; n &amp; " " &amp; (MicroTimer - dTime) * 1000<br />
End Sub</code></p>
<p>The code gets the Range into a Variant, creating a 2-dimensional array, and then loops down the array looking for X and Y.</p>
<h2>Timing Results</h2>
<p>I ran each sub 4 times using different densities of data.</p>
<p>The first is with a single XY pair at row number 100000. This tests the scanning speed per row rather than the calling overhead.</p>
<p>Then I used the Test data generator with constant values of 0.9, 0.5 and 0.001.</p>
<p>Here are the results giving timings in Milliseconds with counts of the XY pairs:</p>
<p><a href="http://fastexcel.files.wordpress.com/2011/10/findmatch1.png"><img class="size-full wp-image-234 alignleft" title="FindMatch1" src="http://fastexcel.files.wordpress.com/2011/10/findmatch1.png?w=450" alt=""   /></a></p>
<p>&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
<br />
And here are the ratios of the times:</p>
<p><a href="http://fastexcel.files.wordpress.com/2011/10/findmatch2.png"><img class="alignleft size-full wp-image-235" title="FindMatch2" src="http://fastexcel.files.wordpress.com/2011/10/findmatch2.png?w=450" alt=""   /></a></p>
<p>&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;<br />
&nbsp;</p>
<ul>
<li>You can see that Find is significantly slower than Match or using a Variant array, regardless of the number of XY pairs found.</li>
<li>The timings for Match increase fast with the number of XY pairs, whereas the Variant array increases much more slowly.</li>
<li>This is because there is a much higher overhead for each call to Match than looping from row to row of the array.</li>
<li>For small numbers of XY pairs Match is faster than the Variant array.</li>
</ul>
<h2>Conclusions</h2>
<ul>
<li><strong>Don&#8217;t use Range.Find unless you want to search a large number of columns for the same thing (you would have to do a Match for each column).</strong></li>
<li><strong>The Variant array approach is surprisingly effective, particularly when you expect a large number of hits.</strong></li>
<li><strong>Match wins easily for a small number of hits.</strong></li>
</ul>
<p><strong>OK, so who is going to admit to using Range.Find?</strong></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/233/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/233/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/233/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=233&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/10/26/match-vs-find-vs-variant-array-vba-performance-shootout/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/10/findmatch1.png" medium="image">
			<media:title type="html">FindMatch1</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/10/findmatch2.png" medium="image">
			<media:title type="html">FindMatch2</media:title>
		</media:content>
	</item>
		<item>
		<title>Writing efficient VBA UDFs (Part 6) &#8211; Faster string handling and Byte arrays</title>
		<link>http://fastexcel.wordpress.com/2011/10/18/writing-efficient-vba-udfs-part-6-faster-strings-and-byte-arrays/</link>
		<comments>http://fastexcel.wordpress.com/2011/10/18/writing-efficient-vba-udfs-part-6-faster-strings-and-byte-arrays/#comments</comments>
		<pubDate>Tue, 18 Oct 2011 12:51:21 +0000</pubDate>
		<dc:creator>fastexcel</dc:creator>
				<category><![CDATA[UDF]]></category>
		<category><![CDATA[VBA]]></category>

		<guid isPermaLink="false">http://fastexcel.wordpress.com/?p=224</guid>
		<description><![CDATA[None of  the previous posts on writing efficient VBA UDfs (Part1,Part2,Part3,Part4,Part5) talked about handling strings in VBA. This could be a major omission since string-handling is one of VBAs slowest &#8220;features&#8221;. Suppose you want to find the position of the first capital letter in a string. Array Formula You could use an array formula like [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=224&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>None of  the previous posts on writing efficient VBA UDfs (<a title="Writing efficient VBA UDFs (Part 1) – It ain’t what you do it’s the way that you do it" href="../2011/05/25/writing-efficient-vba-udfs-part-1/">Part1</a>,<a title="Writing efficient VBA UDFs (Part 2) – using Excel Functions inside a UDF" href="../2011/06/06/writing-efficient-vba-udfs-part-2/">Part2</a>,<a title="Writing efficient VBA UDFs (Part 3) – Avoiding the VBE refresh bug" href="../2011/06/13/writing-efficient-vba-udfs-part-3-avoiding-the-vbe-refresh-bug/">Part3</a>,<a title="Writing efficient VBA UDFs (Part 4) – Variants, References, Arrays, Calculated Expressions, Scalars" href="http://fastexcel.wordpress.com/2011/06/20/writing-efficient-vba-udfs-part-4-variants-references-arrays-calculated-expressions-scalars/">Part4</a>,<a title="Writing efficient VBA UDFs (Part5) – UDF Array Formulas go faster!" href="http://fastexcel.wordpress.com/2011/06/20/writing-efiicient-vba-udfs-part5-udf-array-formulas-go-faster/">Part5</a>) talked about handling strings in VBA.<br />
This could be a major omission since string-handling is one of VBAs slowest &#8220;features&#8221;.</p>
<p>Suppose you want to find the position of the first capital letter in a string.</p>
<h3>Array Formula</h3>
<p>You could use an array formula like this:</p>
<p><strong>{=MATCH(TRUE,ISERR(FIND(MID(A5,ROW($1:$255),1),<br />
LOWER(A5))),0)}</strong></p>
<p>My test data is 2000 rows, each containing 25 lower-case characters and one randomly placed upper-case character.</p>
<p>2000 calls to this array formula takes 250 milliseconds.</p>
<p>So lets try some VBA UDFs.</p>
<h3>Using LIKE</h3>
<p>One way is to use the VBA LIKE statement:<br />
<code><br />
Function FirstCap2(Cell As Range)<br />
For FirstCap2 = 1 To Len(Cell.Value)<br />
If Mid(Cell.Value, FirstCap2, 1) Like "[A-Z]" Then<br />
Exit For<br />
End If<br />
Next FirstCap2<br />
End Function<br />
</code><br />
The code loops across the string using Mid to look at each character in turn, and then uses LIKE to see if the character is one of upper-case A to upper-case Z.<br />
2000 calls to this UDF takes 50 milliseconds &#8211; a factor of 5 faster, but we can make it faster (of course).</p>
<p><code><br />
Function FirstCap3(Rng As Range) As Long<br />
Dim theString As String<br />
theString = Rng.Value2<br />
For FirstCap3 = 1 To Len(theString)<br />
If Mid$(theString, FirstCap3, 1) Like "[A-Z]" Then<br />
Exit For<br />
End If<br />
Next FirstCap3<br />
End Function<br />
</code><br />
I changed the code to only get the string out of the cell once, and to use Mid$ rather than Mid. All the VBA string handling functions have 2 versions: versions without the $ work with variant arguments, whereas versions with the $ suffix only work on string arguments, but are slightly faster.<br />
2000 calls to this version of the UDF takes 17 milliseconds, nearly 3 times faster.</p>
<h3>Using MID$</h3>
<p>But maybe using LIKE is slow? Lets try comparing a lower-case version of the string and stopping when the characters don&#8217;t match:<br />
<code><br />
Function FirstCap4(strInp As String) As Long<br />
Dim tmp As String<br />
Dim i As Long<br />
Dim pos As Long<br />
tmp = LCase$(strInp)<br />
pos = -1<br />
For i = 1 To Len(tmp)<br />
If Mid$(tmp, i, 1) &lt;&gt; Mid$(strInp, i, 1) Then<br />
pos = i<br />
Exit For<br />
End If<br />
Next<br />
FirstCap4 = pos<br />
End Function<br />
</code><br />
Well surprisingly this is <strong>slower</strong> than the optimised version using LIKE:<br />
2000 calls to this version of the UDF takes 36 milliseconds.</p>
<h3>Using Byte Arrays</h3>
<p>Using Byte arrays with strings is one of VBAs less well known secrets, but its often an efficient way of handling strings when you need to inspect each character in turn.</p>
<p><code><br />
Public Function FirstCap5(theRange As Range) As Long<br />
Dim aByte() As Byte<br />
Dim j As Long<br />
FirstCap5 = -1<br />
aByte = theRange.Value2<br />
For j = 0 To UBound(aByte, 1) Step 2<br />
If aByte(j) &lt; 91 Then<br />
If aByte(j) &gt; 64 Then<br />
FirstCap5 = (j + 2) / 2<br />
Exit For<br />
End If<br />
End If<br />
Next j<br />
End Function<br />
</code><br />
This version of the UDF is slightly faster: 2000 calls takes 15 milliseconds.</p>
<p><strong>So how does this work?</strong></p>
<p>First create an undimensioned array of Bytes : Dim aByte() as Byte<br />
Then assign a string to it: aByte=&#8221;abEfg&#8221;<br />
You can use the Locals window to see what the resulting Byte array looks like:</p>
<p><a href="http://fastexcel.files.wordpress.com/2011/10/bytearray.png"><img class="aligncenter size-full wp-image-226" title="Bytearray" src="http://fastexcel.files.wordpress.com/2011/10/bytearray.png?w=450" alt=""   /></a>Each character in the string has resulted in 2 bytes which are the Unicode code points for the character. Since I am working in a UK English Locale using the Windows Latin-1 codepage the first byte is the ANSI number for the character and the second byte is always zero.</p>
<p>Unaccented english upper-case characters are ANSI numbers 65 to 90, so I can loop down the byte array, looking at every other byte, and do a numeric test directly on the character to see if it is upper-case. You can see that only the third character is upper-case.</p>
<p>Another surprising feature of  this kind of Byte array is that you can assign a byte array directly back to a string:<br />
<code><br />
Dim str1 as string<br />
str1=aByte<br />
</code></p>
<p>Str1 now contains &#8220;abEfg&#8221;</p>
<h3>Array version of the Byte UDF</h3>
<p>As discussed in <a title="Writing efficient VBA UDFs (Part5) – UDF Array Formulas go faster!" href="http://fastexcel.wordpress.com/2011/06/20/writing-efiicient-vba-udfs-part5-udf-array-formulas-go-faster/">Part 5</a> of writing efficient UDFs, Array Formulae go faster. So here is an array formula version of the Byte UDF.</p>
<p><code>Public Function AFirstCap(theRange As Range) As Variant<br />
Dim aByte() As Byte<br />
Dim j As Long<br />
Dim L As Long<br />
Dim vRange As Variant<br />
Dim jAnsa() As Long<br />
Dim NumCells As Long<br />
vRange = theRange.Value2<br />
NumCells = UBound(vRange, 1)<br />
ReDim jAnsa(NumCells - 1, 0)<br />
For L = 0 To NumCells - 1<br />
jAnsa(L, 0) = -1<br />
aByte = vRange(L + 1, 1)<br />
For j = 0 To UBound(aByte, 1) Step 2<br />
If aByte(j) &lt; 91 Then<br />
If aByte(j) &gt; 64 Then<br />
jAnsa(L, 0) = (j + 2) / 2<br />
Exit For<br />
End If<br />
End If<br />
Next j<br />
Next L<br />
AFirstCap = jAnsa<br />
End Function</code></p>
<p><code><br />
This version, entered into 2000 rows as an array formula using Control/Shift/Enter, takes just 4.8 milliseconds.</code></p>
<h2>Conclusion</h2>
<p>Here is a table comparing the speed of these different approaches.</p>
<table border="1" cellspacing="0" cellpadding="0">
<tbody>
<tr>
<td valign="top" width="262"><strong>Method</strong></td>
<td valign="top" width="94">
<p align="center"><strong>Milliseconds</strong></p>
</td>
</tr>
<tr>
<td valign="top" width="262">Array Formula</td>
<td valign="top" width="94">
<p align="center">250</p>
</td>
</tr>
<tr>
<td valign="top" width="262">LIKE UDF</td>
<td valign="top" width="94">
<p align="center">50</p>
</td>
</tr>
<tr>
<td valign="top" width="262">Optimised LIKE UDF</td>
<td valign="top" width="94">
<p align="center">17</p>
</td>
</tr>
<tr>
<td valign="top" width="262">MID$ UDF</td>
<td valign="top" width="94">
<p align="center">36</p>
</td>
</tr>
<tr>
<td valign="top" width="262">Byte Array UDF</td>
<td valign="top" width="94">
<p align="center">15</p>
</td>
</tr>
<tr>
<td valign="top" width="262">Array Formula version of Byte Array UDF</td>
<td valign="top" width="94">
<p align="center">4.8</p>
</td>
</tr>
</tbody>
</table>
<p><code>So the fastest VBA is just over 10 times faster than the slowest VBA solution, and a whopping 52 times faster than the array formula solution.</code></p>
<p>Using Byte arrays for strings can be a good solution for string handling where you need to inspect or manipulate many individual characters.</p>
<p><strong>So what do you use Byte arrays for?</strong><code><br />
</code></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/fastexcel.wordpress.com/224/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/fastexcel.wordpress.com/224/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/fastexcel.wordpress.com/224/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=fastexcel.wordpress.com&amp;blog=20833489&amp;post=224&amp;subd=fastexcel&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://fastexcel.wordpress.com/2011/10/18/writing-efficient-vba-udfs-part-6-faster-strings-and-byte-arrays/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/114b7dea411e3648a54fa459c89bed40?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">fastexcel</media:title>
		</media:content>

		<media:content url="http://fastexcel.files.wordpress.com/2011/10/bytearray.png" medium="image">
			<media:title type="html">Bytearray</media:title>
		</media:content>
	</item>
	</channel>
</rss>
