Calling a function as a variable

The functions described in recent posts provide iterative solutions to polynomial equations, but the same method can be used for any equations that can be evaluated numerically and have a single variable.  The question then is, how can we call a function as a variable, rather than hard-coding the function call in the calling function.  The answer lies in the Application.Run method: 

Click for full size view

 

 An example of this method is given in the file PassFunc.xls, which as usual includes full open source code.  The file includes an amended version of the QuadMuller function (and the associated SolvexM function), and a function to evaluate the second moment of area of a segment of a circle about its base, given the radius of the circle and the width of the segment: 

CircIsb Function (click for full size)

 

The calculations performed by the function CircleIsb are: 

Second Moment of Area of a circle segment about its base

 

The formulae for the segment area properties are taken from the Section Properties spreadsheet (version for Excel 2003 and earlier). 

The screenshot below shows an example of the QuadMuller function calling the CircleIsb function to find the width of a circular segment of radius 600 mm with a second moment of area of 5.00E9 mm^4. 

QuadMuller function used with CircleIsb function

 

If using this method to write your own routines note that the arguments to the called function are passed by value, and hence arrays must be declared as variants, rather than explicitly declared as arrays (which can only be passed by reference).  Coincidentally, Tushar Mehta has posted on a similar topic at Daily Dose of Excel and his own site.  His post provides a class based approach, and also gives more details of how the application.run method can be used (in effect) to pass data by reference.

Posted in Arrays, Excel, Maths, UDFs, VBA | Tagged , , , , , , | 6 Comments

The Inverse Quadratic Method – 2

Firstly a clarification from the previous post in this series.  The method presented in that post was a direct application of quadratic interpolation, rather than the inverse quadratic method, as implied by the post title.  The inverse quadratic method will be described in this post, along with Muller’s method which is another variant using quadratic interpolation. 

In the quadratic interpolation method described in the previous post the next approximation of the function root was found in two stages: 

  1. Find the coefficients of the quadratic curve passing through three points of the function
  2. Find the closest root of that quadratic, using the quadratic formula.

In Muller’s method these two stages are combined into one, and the equation used to find the root of the quadratic is less prone to loss of significance; see the Wikipedia article on the topic: 

Mullers Method, click for full size view

 

The procedure for finding the next root approximation is considerably simplified in the Inverse Quadratic Method.  In this method a quadratic curve is fitted to the three points on the function being solved, but using the f(x) values as the x values, and the x values as the f(x) values.  The resulting function may be evaluated directly for x = 0 (i.e. f(x) = 0 in the original function).  Note that the inverse quadratic function is an approximation to the quadratic function through the chosen points, so the root found by this process is not an exact root of the quadratic function. 

The equation for the next root approximation is given by Wikipedia as: 

Inverse Quadratic Function Method, click for full size view

 

Muller’s Method and the Inverse Quadratic Method are now incorporated in the ItSolve Functions.xls spreadsheet, along with full open source code: 

Muller's Method and Inverse Quadratic Method

Posted in Excel, Maths, UDFs, VBA | Tagged , , , , | 3 Comments

Some VBA maths resources

In the past week I have discovered a couple of  sites with open source maths related VBA code that I was previously unaware of, and which deserve to be better known:

AlgLib:

“ALGLIB is a cross-platform numerical analysis and data processing library. ALGLIB aims to be highly portable: it supports several programming languages (C++, C# and other languages); it may be compiled with a wide variety of compilers and was tested under a wide variety of platforms. And it is free – ALGLIB is distributed under a GPL license (version 2 or later).”

All of the code is provided in VBA as well as various flavours of C and Fortran, and appears to be well documented and indexed.  This makes it ideal for creating prototypes in VBA, and if desired converting to compiled dlls at a later date.

Axel Vogt

Axel’s home page sets new standards for minimal web site design, here it is in full:

axalom
various files for numerical or financial Math, free for download

But don’t be put off, there are many worthwhile files here, as well as some excellent articles on programming topics.

Posted in Arrays, Excel, Maths, VBA | Tagged , , | 4 Comments

Function roots with the Inverse Quadratic Method

An earlier post presented various methods for finding the roots of polynomial functions based on the use of linear interpolation.  It is sometimes advantageous to use a quadratic interpolation function, and methods using this approach will be presented in this and following posts.  The earlier functions and the new quadratic interpolation functions have been incorporated in the spreadsheet ItSolve Functions.xls

Any three points on a plane (other than co-linear points) will define a unique quadratic curve of the form ax2 + bx + c = 0.  The User Defined Function (UDF) FITQUAD returns an array of the three coefficients, a, b and c: 

 A = ((Y2 – Y1) * (X1 – X3) + (Y3 – Y1) * (X2 – X1)) / ((X1 – X3) * (X2 ^ 2 – X1 ^ 2) + (X2 – X1) * (X3 ^ 2 – X1 ^ 2))
B = ((Y2 – Y1) – A * (X2 ^ 2 – X1 ^ 2)) / (X2 – X1)
C = Y1 – A * X1 ^ 2 – B * X1 

This quadratic equation may then be solved in the usual way to find the x values for which it evaluates to zero.  The procedure for applying this method to evaluating the roots of higher order functions is: 

  • Select three known points on the function to be solved, in the region of the solution of interest, with at least one point on each side of the x-axis
  • Fit a quadratic curve to these three points
  • Find the root of the quadratic curve in the range of interest
  • Find the y value of the higher order function at this x value.
  • Replace the furthest outlying of the three trial points with this new point.
  • Repeat until the error is acceptably small.

The screenshot below shows this procedure carried out on the spreadsheet, using the FitQuad function: 

Click to view full size

 

The process is automated using the UDF QuadSolve(): 

Inverse Quadratic Interpolation with QuadSolve

Posted in Excel, Maths, UDFs, VBA | Tagged , , , , | 5 Comments

Transferring data with arrays

The earlier post: Transferring data within VBA looked at some important aspects of transferring data between subroutines in Excel VBA.  This post will look at arrays in particular, and some peculiarities that affect the way they work.

VBA arrays are a very convenient data structure to use in combination with a spreadsheet, not least because conceptually they are very similar to the arrangement of data in a spreadsheet.  Previous posts have examined the ways of transferring data between a spreadsheet and VBA (select arrays in the category box to the left for a listing), and this post will look at the ways of handling arrays within VBA.

Arrays may be declared in VBA in one of two ways; either explicitly:

Dim Array1(1 to 10, 1 to 2) as double

or implicitly:

 Dim Array1(1 to 10, 1 to 2) as Double, Array2 as Variant
...
Array2 = Array1

In the second case Array2 is created as type Variant/Empty when it is declared, then after assignment it becomes a variant Array of the same type as the array it was assigned to; in this case Variant/Double(1 to 10, 1 to 2).  Reasons for declaring an array in this way include:

  • It is the most efficient way of passing data from and to a spreadsheet (see earlier posts on the subject)
  • It allows the contents of an array to be passed to another subroutine by value (see later in this post)
  • It allows one or more copies of the array to be made, without looping through each element of the array

With regard to the final point, note that the code below will not work:

Sub ArraySub2()
Dim Array1(1 To 10, 1 To 2) As Double, Array2(1 To 10, 1 To 2) As Double
Array2 = Array1
End Sub

This will generate the compile time error: Can’t assign to array

To assign one array to another, the second array must either be declared as a variant, or the array must be dynamic, that is it must be declared without specifying the dimensions:

Sub ArraySub3()
Dim Array1(1 To 10, 1 To 2) As Double, Array2 As Variant, Array3() As Double
Array2 = Array1
Array3 = Array1
End Sub

In this code Array3 will be of type Double() after being declared, then type Double(1 to 10, 1 to 2) after the assignment.

An array that has been declared as dynamic (i.e. with no stated dimension data at the time of declaration) may be dimensioned at any time with a ReDim statement, but remains dynamic:

Sub ArraySub4()
Dim Array1(1 To 10, 1 To 2) As Double, Array2 As Variant, Array3() As Double
ReDim Array3(1 To 20, 1 To 1)
Array2 = Array1
Array3 = Array1
End Sub

In this routine Array3 has dimensions (1 to 20, 1 to 1) after the ReDim statement, but (1 to 10, 1 to 2) after the assignment to Array1.

Arrays may be passed to and from other routines, but there are a number of important restrictions:

  • An array declared as an array (whether static or dynamic) can only be passed by reference, not by value.
  • A variant array (declared as a variant) may be passed by reference or by value (by reference is the default, as usual)
  • If a function return value is desired to be an array the function must be declared as a variant
  • Declaring the function as a variant is the only way that a user defined function may be used in a worksheet to return an array.
  • Arrays must either be declared as dynamic or as variant arrays in the called routine

These points are illustrated in the code below:

Sub ArraySub5()
Dim Array1(1 To 10, 1 To 2) As Double, Array2 As Variant, Array3() As Double, Array4 As Variant
ReDim Array3(1 To 20, 1 To 1)
Array4 = ArrayFunc1(Array1, Array2, Array3)
End Sub


Function ArrayFunc1(Array1() As Double, ByVal Array2 As Variant, Array3() As Double) As Variant
Dim ArrayF4(1 To 10, 1 To 2) As Double
ReDim Array3(1 To 10, 1 To 2)
ArrayFunc1 = ArrayF4
End Function

If you step through this routine you will observe that:

  • Array1 is passed to the function with dimensions (1 to 10, 1 to 2)
  • In the Function Array1 is assigned to Array2, a variant array, but because Array2 was passed by value this does not affect the status of Array2 in the calling routine.
  • Array3 is dimensioned to (1 to 10, 1 to 2) in the function, and because the array was passed by reference (the default and only option for an explicit array) this change is relected in the Array3 in the calling routine.
  • ArrayF4 is declared as a static array in the function, but because the function is declared as a variant the return value is a variant array of doubles, and Array4 in the calling routine becomes the same type after the function return value is assigned to it.
Posted in Arrays, Excel, VBA | Tagged , , , , , , , | Leave a comment