Excel VBA method ROUND is incorrect - excel

Public Function foo()
Dim x As Double, y As Double, z As Double
x = 1.26
y = 3.175
z = Round(x + y, 2)
foo = z
End Function
Running Excel 2007 on Windows 7. This function returns 4.43 into a cell with =foo() which is annoying as I want 4.44. I found some documentation claiming VBA ROUND uses even rounding but here the last digit is odd. What is wrong here?

You can always use the Worksheet Round Function instead of VBA's built-in one
Public Function foo2()
Dim x As Double, y As Double, z As Double
x = 1.26
y = 3.175
z = Application.WorksheetFunction.Round(x + y, 2)
foo2 = z
End Function
foo2 will result in 4.44 (tested on my machine). I don't know if this would affect performance at all.

You will need to use decimal types to accomplish this which uses integer based arithmetic as opposed to floating point based.
Excel doesn't have a native data type for this, so you have to use a Variant and then convert to a decimal using the CDec function.
Public Function foo()
Dim x As Variant, y As Variant, z As Variant
x = CDec(1.26)
y = CDec(3.175)
z = Round(x + y, 2)
foo = z
End Function

While Excel.WorksheetFunction.Round does perform correct 4/5 rounding, it is terribly slow and, of course, requires Excel to be installed.
For fast and precise rounding of any value - up, down, 4/5, Banker's, significant digits, Base 2 or Base 10, and more - go to my project VBA.Round.

Related

How to declare numeric variables?

Numeric variables give
Run Time 6` error
It all seems to be related to the way Excel on MacOs handles these declarations. I find with Integer, Single, and Double if you do a division you get the error.
Dim x, y as double
x=2
y=2 'error 6
x=x/2
y=y/2 'error6
End Sub
If you put x and y in Watch window you will see they are not showing as Double; instead, x is displayed as Variant/String, y as String.
The Variant/String performs ok, the string does not.
MS Docs state that Dim x,y As Double will declare both to be doubles. Others, who I assume are on Windows, say not, that you must say Dim x As Double, y As Double; but in this case, even that does not work.
MacOs Excel Version 16.43
This is the correct syntax:
Dim x As Double
Dim y As Double
x = 2
y = 2
x = x / 2
y = y / 2
' No error.

Why is a ByVal function changing my variable?

Calling divsig(h) results in changes to h. But divsig is a function that takes a matrix by value and not by reference. How can this happen?
I'm trying to use the sig/divsig functions on matrices of data, for example:
DenseMatrix 4x4-Double ' h before divsig(h)
0.5 0.5 0.5 0.5
0.568811 0.995811 0.418727 0.987232
0.65701 0.269138 0.990942 0.99298
0.716466 0.988705 0.98747 0.999909
divsig(h)
DenseMatrix 4x4-Double ' h after divsig
0.25 0.25 0.25 0.25
0.245265 0.00417185 0.243395 0.0126045
0.225348 0.196703 0.00897602 0.00697036
0.203142 0.0111678 0.0123732 9.14075E-05
Makes no sense to me what so ever, i'm even setting up a new variable called matrix in the function instead of editing 'mat' it's self.
Function divsig(ByVal mat As LinearAlgebra.Double.Matrix)
Dim matrix = mat
For _x = 0 To matrix.RowCount() - 1
For _y = 0 To matrix.ColumnCount() - 1
matrix(_x, _y) = derivsigmoid(matrix(_x, _y))
Next
Next
Return matrix
End Function
Function sigmoid(ByVal x As Double) As Double
Return 1 / (1 + Math.Exp(-x))
End Function
Function derivsigmoid(ByVal x As Double) As Double
Return x * (1 - x)
End Function
Function sig(ByVal mat As LinearAlgebra.Double.Matrix)
Dim matrix = mat
For _x = 0 To matrix.RowCount() - 1
For _y = 0 To matrix.ColumnCount() - 1
matrix(_x, _y) = sigmoid(matrix(_x, _y))
Next
Next
Return matrix
End Function
I have fixed it, turns out matrixes are classes which means passing them ByVal passes the reference anyway. I fixed it by replacing the Dim matrix = mat with
Dim matrix As LinearAlgebra.Double.Matrix = LinearAlgebra.Double.Matrix.Build.DenseOfMatrix(mat)
So matrix becomes a copy of mat instead of just giving the same reference a different identifier.

How do i Square Root a Function in VBA

I am working on a MonteCarlo simulation model and part of it is to calculate the following formula:
X = Sqr(1-p)Y + Sqr(p)Z,
Where:
Y and Z are randomly obtained values based (idiosyncratic and systematic factors, respectviely) on a standard normal (inv.) distribution, calculated as:
Application.WorksheetFunction.NormInv (Rnd(), mean, sd)
p represents a correlation factor.
My aim is to square root a recalled formula, however when I try the following (inserting the first Sqr), it does not work and gives an error:
Matrix (n, sims) = (R * Sqr(Application.WorksheetFunction.NormInv(Rnd(), mean, sd))) + (Sqr(1 - R) * RandomS(s, x))
where:
R: Correlation factor
RandomS(s,x): generated matrix with Z values.
I don't want to go into too much details about the background and other variables, as the only problem I am getting is with Square Rooting the equation.
Error message I recieve reads:
Run-time error '5':
Invalid procedure call or argument
When I click debug it takes me to the formula, therefore there must be something wrong with the syntax.
Can you help with directly squaring the formula?
Thank you!
Andrew
Square root is simply Sqr.
It works fine in Excel VBA, so for example:
MsgBox Sqr(144)
...returns 12.
Just don't confuse it with the syntax for a worksheet function with is SQRT.
If you're still having an issue with your formula, tit must be with something other than the Square Root function, and I'd suggest you check the values of your variable, and make sure they are properly declared (preferably with Option Explicit at the top of the module).
Also make sure that you're passing Sqr a positive number.
Documentation: Sqr Function
I'm not a math major, but with your formula:
X = Sqr(1-p)Y + Sqr(p)Z,
...you specified how Y and Z are calculated, so calculate them separately to keep it simple:
Dim X as Double, Y as Double, Z as Double
Y = Application.WorksheetFunction.NormInv (Rnd(), mean, sd)
Z = Application.WorksheetFunction.NormInv (Rnd(), mean, sd)
Assuming the comma is not supposed to be in the formula, and having no idea what p is, your final code to calculate X is:
X = Sqr(1-p) * Y + Sqr(p) * Z

Test Visual Basic Scripts behind an Excel Spreadsheet

First of all I need to point out that I have never coded Visual Basic before.
I have an old spreadsheet which has some functions that are apparently written in Visual Basic. An example functions is:
Function Helmert_X(X, Y, Z, DX, Y_Rot, Z_Rot, s)
'Computed Helmert transformed X coordinate.
'Input: - _
cartesian XYZ coords (X,Y,Z), X translation (DX) all in meters ; _
Y and Z rotations in seconds of arc (Y_Rot, Z_Rot) and scale in ppm (s).
'Convert rotations to radians and ppm scale to a factor
Pi = 3.14159265358979
sfactor = s * 0.000001
RadY_Rot = (Y_Rot / 3600) * (Pi / 180)
RadZ_Rot = (Z_Rot / 3600) * (Pi / 180)
'Compute transformed X coord
Helmert_X = X + (X * sfactor) - (Y * RadZ_Rot) + (Z * RadY_Rot) + DX
End Function
I'm trying to convert these functions into C. I have almost finished but what I would like to do is to build a visual basic project that calls the functions with various parameters. Then I will have a C project which uses the same parameters and checks that the C gets the same answers as the Visual Basic.
When I put the Visual Basic functions into a Module in Visual Studio I get a lot of errors. Firstly the comments don't all register as comments, and the variables apparently need to be declared.
Am I using the functions properly? Is there anyway to use them in code without modifying them? Could I use Excel to run test parameters through the functions?
It seems you need to declare all variables that exist in that function. Try to add theses lines after the comments:
Dim Pi As Double
Dim sfactor As Double
Dim RadY_Rot As Double
Dim RadZ_Rot As Double
You can also specify type for variables that came with function, as well the function itself:
Function Helmert_X(X as Double, Y as Double, Z as Double, DX as Double, Y_Rot as Double, Z_Rot as Double, s as Double) as Double
Let me know if it works or if there is still some issue.

Scaled Complementary Error Function, erfcx(x), computation avoiding arithmetic overflow - VBA/Excel

I need an algorithm/approximation to compute the Scaled Complementary Error Function, erfcx(x) to double-float precision.
I'm on a work PC so I’m limited to using Excel and VBA and I cannot use external libraries or add-ins: I need to code this myself.
Excel only provides erf() and erfc() functions.
The relationship erfcx(x) = exp(x^2) erfc(x) is obviously useful, however there is arithmetic over/underflow for x larger than around 26.5 and I need to go larger than this.
The below post discussed a python implementation – but it doesn’t seem to resolve the issue from what I can tell. It provides solutions using other libraries or an approximation that isn’t precise enough for my needs.
Is there a scaled complementary error function in python available?
Any suggestions?
Update:
I used this Continued Fraction representation I found on Wikipedia
and a modified version of the algorithm for solving continued fractions found here http://finance4traders.blogspot.nl/2009/07/continued-fractions-and-modified-lentzs.html
The following code seems to work and actually takes fewer iterations for larger input parameters.
Function erfcx(x) As Variant
Dim Ai As Double
Dim Bi As Double
Dim Ci As Double
Dim Di As Double
Dim Ei As Double
Dim Fi As Double
Dim X2 As Double
Dim i As Long
Const SQRPI As Double = 1.7724538509055
Const MAX_ITERATIONS = 1000
If x < 26.5 Then
erfcx = Application.WorksheetFunction.ErfC_Precise(x) * Exp(x ^ 2)
Else
X2 = x ^ 2
Bi = X2
Fi = X2
Ci = X2
Di = 0
Do
i = i + 1
Ai = i / 2
If i Mod 2 = 0 Then
Bi = X2
Else
Bi = 1
End If
Di = 1 / (Bi + Ai * Di)
Ci = Bi + Ai / Ci
Ei = Ci * Di
Fi = Fi * Ei
Loop While Ei <> 1 And i < MAX_ITERATIONS
Debug.Print i
erfcx = x / Fi / SQRPI
End If End function
Several approximations are discuss here:
AMS Journal Article
Once you have determined which approximation is suitable, we can help you code it in either a worksheet function or a VBA UDF()

Resources